xref: /openbmc/linux/drivers/ata/sata_mv.c (revision 4a05e209)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  * sata_mv.c - Marvell SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  * Copyright 2005: EMC Corporation, all rights reserved.
5c6fd2807SJeff Garzik  * Copyright 2005 Red Hat, Inc.  All rights reserved.
6c6fd2807SJeff Garzik  *
7c6fd2807SJeff Garzik  * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
8c6fd2807SJeff Garzik  *
9c6fd2807SJeff Garzik  * This program is free software; you can redistribute it and/or modify
10c6fd2807SJeff Garzik  * it under the terms of the GNU General Public License as published by
11c6fd2807SJeff Garzik  * the Free Software Foundation; version 2 of the License.
12c6fd2807SJeff Garzik  *
13c6fd2807SJeff Garzik  * This program is distributed in the hope that it will be useful,
14c6fd2807SJeff Garzik  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c6fd2807SJeff Garzik  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16c6fd2807SJeff Garzik  * GNU General Public License for more details.
17c6fd2807SJeff Garzik  *
18c6fd2807SJeff Garzik  * You should have received a copy of the GNU General Public License
19c6fd2807SJeff Garzik  * along with this program; if not, write to the Free Software
20c6fd2807SJeff Garzik  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21c6fd2807SJeff Garzik  *
22c6fd2807SJeff Garzik  */
23c6fd2807SJeff Garzik 
244a05e209SJeff Garzik /*
254a05e209SJeff Garzik   sata_mv TODO list:
264a05e209SJeff Garzik 
274a05e209SJeff Garzik   1) Needs a full errata audit for all chipsets.  I implemented most
284a05e209SJeff Garzik   of the errata workarounds found in the Marvell vendor driver, but
294a05e209SJeff Garzik   I distinctly remember a couple workarounds (one related to PCI-X)
304a05e209SJeff Garzik   are still needed.
314a05e209SJeff Garzik 
324a05e209SJeff Garzik   2) Convert to LibATA new EH.  Required for hotplug, NCQ, and sane
334a05e209SJeff Garzik   probing/error handling in general.  MUST HAVE.
344a05e209SJeff Garzik 
354a05e209SJeff Garzik   3) Add hotplug support (easy, once new-EH support appears)
364a05e209SJeff Garzik 
374a05e209SJeff Garzik   4) Add NCQ support (easy to intermediate, once new-EH support appears)
384a05e209SJeff Garzik 
394a05e209SJeff Garzik   5) Investigate problems with PCI Message Signalled Interrupts (MSI).
404a05e209SJeff Garzik 
414a05e209SJeff Garzik   6) Add port multiplier support (intermediate)
424a05e209SJeff Garzik 
434a05e209SJeff Garzik   7) Test and verify 3.0 Gbps support
444a05e209SJeff Garzik 
454a05e209SJeff Garzik   8) Develop a low-power-consumption strategy, and implement it.
464a05e209SJeff Garzik 
474a05e209SJeff Garzik   9) [Experiment, low priority] See if ATAPI can be supported using
484a05e209SJeff Garzik   "unknown FIS" or "vendor-specific FIS" support, or something creative
494a05e209SJeff Garzik   like that.
504a05e209SJeff Garzik 
514a05e209SJeff Garzik   10) [Experiment, low priority] Investigate interrupt coalescing.
524a05e209SJeff Garzik   Quite often, especially with PCI Message Signalled Interrupts (MSI),
534a05e209SJeff Garzik   the overhead reduced by interrupt mitigation is quite often not
544a05e209SJeff Garzik   worth the latency cost.
554a05e209SJeff Garzik 
564a05e209SJeff Garzik   11) [Experiment, Marvell value added] Is it possible to use target
574a05e209SJeff Garzik   mode to cross-connect two Linux boxes with Marvell cards?  If so,
584a05e209SJeff Garzik   creating LibATA target mode support would be very interesting.
594a05e209SJeff Garzik 
604a05e209SJeff Garzik   Target mode, for those without docs, is the ability to directly
614a05e209SJeff Garzik   connect two SATA controllers.
624a05e209SJeff Garzik 
634a05e209SJeff Garzik   13) Verify that 7042 is fully supported.  I only have a 6042.
644a05e209SJeff Garzik 
654a05e209SJeff Garzik */
664a05e209SJeff Garzik 
674a05e209SJeff Garzik 
68c6fd2807SJeff Garzik #include <linux/kernel.h>
69c6fd2807SJeff Garzik #include <linux/module.h>
70c6fd2807SJeff Garzik #include <linux/pci.h>
71c6fd2807SJeff Garzik #include <linux/init.h>
72c6fd2807SJeff Garzik #include <linux/blkdev.h>
73c6fd2807SJeff Garzik #include <linux/delay.h>
74c6fd2807SJeff Garzik #include <linux/interrupt.h>
75c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
76c6fd2807SJeff Garzik #include <linux/device.h>
77c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
78c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
79c6fd2807SJeff Garzik #include <linux/libata.h>
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik #define DRV_NAME	"sata_mv"
828bc3fc47SJeff Garzik #define DRV_VERSION	"0.81"
83c6fd2807SJeff Garzik 
84c6fd2807SJeff Garzik enum {
85c6fd2807SJeff Garzik 	/* BAR's are enumerated in terms of pci_resource_start() terms */
86c6fd2807SJeff Garzik 	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */
87c6fd2807SJeff Garzik 	MV_IO_BAR		= 2,	/* offset 0x18: IO space */
88c6fd2807SJeff Garzik 	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */
89c6fd2807SJeff Garzik 
90c6fd2807SJeff Garzik 	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */
91c6fd2807SJeff Garzik 	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */
92c6fd2807SJeff Garzik 
93c6fd2807SJeff Garzik 	MV_PCI_REG_BASE		= 0,
94c6fd2807SJeff Garzik 	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
95c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
96c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
97c6fd2807SJeff Garzik 	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
98c6fd2807SJeff Garzik 	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
99c6fd2807SJeff Garzik 	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
100c6fd2807SJeff Garzik 
101c6fd2807SJeff Garzik 	MV_SATAHC0_REG_BASE	= 0x20000,
102c6fd2807SJeff Garzik 	MV_FLASH_CTL		= 0x1046c,
103c6fd2807SJeff Garzik 	MV_GPIO_PORT_CTL	= 0x104f0,
104c6fd2807SJeff Garzik 	MV_RESET_CFG		= 0x180d8,
105c6fd2807SJeff Garzik 
106c6fd2807SJeff Garzik 	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,
107c6fd2807SJeff Garzik 	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,
108c6fd2807SJeff Garzik 	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
109c6fd2807SJeff Garzik 	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
110c6fd2807SJeff Garzik 
111c6fd2807SJeff Garzik 	MV_USE_Q_DEPTH		= ATA_DEF_QUEUE,
112c6fd2807SJeff Garzik 
113c6fd2807SJeff Garzik 	MV_MAX_Q_DEPTH		= 32,
114c6fd2807SJeff Garzik 	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
115c6fd2807SJeff Garzik 
116c6fd2807SJeff Garzik 	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
117c6fd2807SJeff Garzik 	 * CRPB needs alignment on a 256B boundary. Size == 256B
118c6fd2807SJeff Garzik 	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
119c6fd2807SJeff Garzik 	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
120c6fd2807SJeff Garzik 	 */
121c6fd2807SJeff Garzik 	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
122c6fd2807SJeff Garzik 	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
123c6fd2807SJeff Garzik 	MV_MAX_SG_CT		= 176,
124c6fd2807SJeff Garzik 	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
125c6fd2807SJeff Garzik 	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
126c6fd2807SJeff Garzik 
127c6fd2807SJeff Garzik 	MV_PORTS_PER_HC		= 4,
128c6fd2807SJeff Garzik 	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
129c6fd2807SJeff Garzik 	MV_PORT_HC_SHIFT	= 2,
130c6fd2807SJeff Garzik 	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
131c6fd2807SJeff Garzik 	MV_PORT_MASK		= 3,
132c6fd2807SJeff Garzik 
133c6fd2807SJeff Garzik 	/* Host Flags */
134c6fd2807SJeff Garzik 	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
135c6fd2807SJeff Garzik 	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
136c6fd2807SJeff Garzik 	MV_COMMON_FLAGS		= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
137c6fd2807SJeff Garzik 				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
138c6fd2807SJeff Garzik 				   ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
139c6fd2807SJeff Garzik 	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,
140c6fd2807SJeff Garzik 
141c6fd2807SJeff Garzik 	CRQB_FLAG_READ		= (1 << 0),
142c6fd2807SJeff Garzik 	CRQB_TAG_SHIFT		= 1,
143c6fd2807SJeff Garzik 	CRQB_CMD_ADDR_SHIFT	= 8,
144c6fd2807SJeff Garzik 	CRQB_CMD_CS		= (0x2 << 11),
145c6fd2807SJeff Garzik 	CRQB_CMD_LAST		= (1 << 15),
146c6fd2807SJeff Garzik 
147c6fd2807SJeff Garzik 	CRPB_FLAG_STATUS_SHIFT	= 8,
148c6fd2807SJeff Garzik 
149c6fd2807SJeff Garzik 	EPRD_FLAG_END_OF_TBL	= (1 << 31),
150c6fd2807SJeff Garzik 
151c6fd2807SJeff Garzik 	/* PCI interface registers */
152c6fd2807SJeff Garzik 
153c6fd2807SJeff Garzik 	PCI_COMMAND_OFS		= 0xc00,
154c6fd2807SJeff Garzik 
155c6fd2807SJeff Garzik 	PCI_MAIN_CMD_STS_OFS	= 0xd30,
156c6fd2807SJeff Garzik 	STOP_PCI_MASTER		= (1 << 2),
157c6fd2807SJeff Garzik 	PCI_MASTER_EMPTY	= (1 << 3),
158c6fd2807SJeff Garzik 	GLOB_SFT_RST		= (1 << 4),
159c6fd2807SJeff Garzik 
160c6fd2807SJeff Garzik 	MV_PCI_MODE		= 0xd00,
161c6fd2807SJeff Garzik 	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,
162c6fd2807SJeff Garzik 	MV_PCI_DISC_TIMER	= 0xd04,
163c6fd2807SJeff Garzik 	MV_PCI_MSI_TRIGGER	= 0xc38,
164c6fd2807SJeff Garzik 	MV_PCI_SERR_MASK	= 0xc28,
165c6fd2807SJeff Garzik 	MV_PCI_XBAR_TMOUT	= 0x1d04,
166c6fd2807SJeff Garzik 	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,
167c6fd2807SJeff Garzik 	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,
168c6fd2807SJeff Garzik 	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,
169c6fd2807SJeff Garzik 	MV_PCI_ERR_COMMAND	= 0x1d50,
170c6fd2807SJeff Garzik 
171c6fd2807SJeff Garzik 	PCI_IRQ_CAUSE_OFS		= 0x1d58,
172c6fd2807SJeff Garzik 	PCI_IRQ_MASK_OFS		= 0x1d5c,
173c6fd2807SJeff Garzik 	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
174c6fd2807SJeff Garzik 
175c6fd2807SJeff Garzik 	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
176c6fd2807SJeff Garzik 	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
177c6fd2807SJeff Garzik 	PORT0_ERR		= (1 << 0),	/* shift by port # */
178c6fd2807SJeff Garzik 	PORT0_DONE		= (1 << 1),	/* shift by port # */
179c6fd2807SJeff Garzik 	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
180c6fd2807SJeff Garzik 	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
181c6fd2807SJeff Garzik 	PCI_ERR			= (1 << 18),
182c6fd2807SJeff Garzik 	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
183c6fd2807SJeff Garzik 	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
184fb621e2fSJeff Garzik 	PORTS_0_3_COAL_DONE	= (1 << 8),
185fb621e2fSJeff Garzik 	PORTS_4_7_COAL_DONE	= (1 << 17),
186c6fd2807SJeff Garzik 	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
187c6fd2807SJeff Garzik 	GPIO_INT		= (1 << 22),
188c6fd2807SJeff Garzik 	SELF_INT		= (1 << 23),
189c6fd2807SJeff Garzik 	TWSI_INT		= (1 << 24),
190c6fd2807SJeff Garzik 	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
191fb621e2fSJeff Garzik 	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
192c6fd2807SJeff Garzik 	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
193c6fd2807SJeff Garzik 				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
194c6fd2807SJeff Garzik 				   HC_MAIN_RSVD),
195fb621e2fSJeff Garzik 	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
196fb621e2fSJeff Garzik 				   HC_MAIN_RSVD_5),
197c6fd2807SJeff Garzik 
198c6fd2807SJeff Garzik 	/* SATAHC registers */
199c6fd2807SJeff Garzik 	HC_CFG_OFS		= 0,
200c6fd2807SJeff Garzik 
201c6fd2807SJeff Garzik 	HC_IRQ_CAUSE_OFS	= 0x14,
202c6fd2807SJeff Garzik 	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
203c6fd2807SJeff Garzik 	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
204c6fd2807SJeff Garzik 	DEV_IRQ			= (1 << 8),	/* shift by port # */
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik 	/* Shadow block registers */
207c6fd2807SJeff Garzik 	SHD_BLK_OFS		= 0x100,
208c6fd2807SJeff Garzik 	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
209c6fd2807SJeff Garzik 
210c6fd2807SJeff Garzik 	/* SATA registers */
211c6fd2807SJeff Garzik 	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
212c6fd2807SJeff Garzik 	SATA_ACTIVE_OFS		= 0x350,
213c6fd2807SJeff Garzik 	PHY_MODE3		= 0x310,
214c6fd2807SJeff Garzik 	PHY_MODE4		= 0x314,
215c6fd2807SJeff Garzik 	PHY_MODE2		= 0x330,
216c6fd2807SJeff Garzik 	MV5_PHY_MODE		= 0x74,
217c6fd2807SJeff Garzik 	MV5_LT_MODE		= 0x30,
218c6fd2807SJeff Garzik 	MV5_PHY_CTL		= 0x0C,
219c6fd2807SJeff Garzik 	SATA_INTERFACE_CTL	= 0x050,
220c6fd2807SJeff Garzik 
221c6fd2807SJeff Garzik 	MV_M2_PREAMP_MASK	= 0x7e0,
222c6fd2807SJeff Garzik 
223c6fd2807SJeff Garzik 	/* Port registers */
224c6fd2807SJeff Garzik 	EDMA_CFG_OFS		= 0,
225c6fd2807SJeff Garzik 	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
226c6fd2807SJeff Garzik 	EDMA_CFG_NCQ		= (1 << 5),
227c6fd2807SJeff Garzik 	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
228c6fd2807SJeff Garzik 	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
229c6fd2807SJeff Garzik 	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
230c6fd2807SJeff Garzik 
231c6fd2807SJeff Garzik 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
232c6fd2807SJeff Garzik 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
233c6fd2807SJeff Garzik 	EDMA_ERR_D_PAR		= (1 << 0),
234c6fd2807SJeff Garzik 	EDMA_ERR_PRD_PAR	= (1 << 1),
235c6fd2807SJeff Garzik 	EDMA_ERR_DEV		= (1 << 2),
236c6fd2807SJeff Garzik 	EDMA_ERR_DEV_DCON	= (1 << 3),
237c6fd2807SJeff Garzik 	EDMA_ERR_DEV_CON	= (1 << 4),
238c6fd2807SJeff Garzik 	EDMA_ERR_SERR		= (1 << 5),
239c6fd2807SJeff Garzik 	EDMA_ERR_SELF_DIS	= (1 << 7),
240c6fd2807SJeff Garzik 	EDMA_ERR_BIST_ASYNC	= (1 << 8),
241c6fd2807SJeff Garzik 	EDMA_ERR_CRBQ_PAR	= (1 << 9),
242c6fd2807SJeff Garzik 	EDMA_ERR_CRPB_PAR	= (1 << 10),
243c6fd2807SJeff Garzik 	EDMA_ERR_INTRL_PAR	= (1 << 11),
244c6fd2807SJeff Garzik 	EDMA_ERR_IORDY		= (1 << 12),
245c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),
246c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
247c6fd2807SJeff Garzik 	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),
248c6fd2807SJeff Garzik 	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),
249c6fd2807SJeff Garzik 	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),
250c6fd2807SJeff Garzik 	EDMA_ERR_TRANS_PROTO	= (1 << 31),
251c6fd2807SJeff Garzik 	EDMA_ERR_FATAL		= (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
252c6fd2807SJeff Garzik 				   EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
253c6fd2807SJeff Garzik 				   EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
254c6fd2807SJeff Garzik 				   EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
255c6fd2807SJeff Garzik 				   EDMA_ERR_LNK_DATA_RX |
256c6fd2807SJeff Garzik 				   EDMA_ERR_LNK_DATA_TX |
257c6fd2807SJeff Garzik 				   EDMA_ERR_TRANS_PROTO),
258c6fd2807SJeff Garzik 
259c6fd2807SJeff Garzik 	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
260c6fd2807SJeff Garzik 	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
261c6fd2807SJeff Garzik 
262c6fd2807SJeff Garzik 	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
263c6fd2807SJeff Garzik 	EDMA_REQ_Q_PTR_SHIFT	= 5,
264c6fd2807SJeff Garzik 
265c6fd2807SJeff Garzik 	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
266c6fd2807SJeff Garzik 	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
267c6fd2807SJeff Garzik 	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
268c6fd2807SJeff Garzik 	EDMA_RSP_Q_PTR_SHIFT	= 3,
269c6fd2807SJeff Garzik 
270c6fd2807SJeff Garzik 	EDMA_CMD_OFS		= 0x28,
271c6fd2807SJeff Garzik 	EDMA_EN			= (1 << 0),
272c6fd2807SJeff Garzik 	EDMA_DS			= (1 << 1),
273c6fd2807SJeff Garzik 	ATA_RST			= (1 << 2),
274c6fd2807SJeff Garzik 
275c6fd2807SJeff Garzik 	EDMA_IORDY_TMOUT	= 0x34,
276c6fd2807SJeff Garzik 	EDMA_ARB_CFG		= 0x38,
277c6fd2807SJeff Garzik 
278c6fd2807SJeff Garzik 	/* Host private flags (hp_flags) */
279c6fd2807SJeff Garzik 	MV_HP_FLAG_MSI		= (1 << 0),
280c6fd2807SJeff Garzik 	MV_HP_ERRATA_50XXB0	= (1 << 1),
281c6fd2807SJeff Garzik 	MV_HP_ERRATA_50XXB2	= (1 << 2),
282c6fd2807SJeff Garzik 	MV_HP_ERRATA_60X1B2	= (1 << 3),
283c6fd2807SJeff Garzik 	MV_HP_ERRATA_60X1C0	= (1 << 4),
284c6fd2807SJeff Garzik 	MV_HP_ERRATA_XX42A0	= (1 << 5),
285c6fd2807SJeff Garzik 	MV_HP_50XX		= (1 << 6),
286c6fd2807SJeff Garzik 	MV_HP_GEN_IIE		= (1 << 7),
287c6fd2807SJeff Garzik 
288c6fd2807SJeff Garzik 	/* Port private flags (pp_flags) */
289c6fd2807SJeff Garzik 	MV_PP_FLAG_EDMA_EN	= (1 << 0),
290c6fd2807SJeff Garzik 	MV_PP_FLAG_EDMA_DS_ACT	= (1 << 1),
291c6fd2807SJeff Garzik };
292c6fd2807SJeff Garzik 
293c6fd2807SJeff Garzik #define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
294c6fd2807SJeff Garzik #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
295c6fd2807SJeff Garzik #define IS_GEN_I(hpriv) IS_50XX(hpriv)
296c6fd2807SJeff Garzik #define IS_GEN_II(hpriv) IS_60XX(hpriv)
297c6fd2807SJeff Garzik #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
298c6fd2807SJeff Garzik 
299c6fd2807SJeff Garzik enum {
300d88184fbSJeff Garzik 	MV_DMA_BOUNDARY		= 0xffffffffU,
301c6fd2807SJeff Garzik 
302c6fd2807SJeff Garzik 	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
303c6fd2807SJeff Garzik 
304c6fd2807SJeff Garzik 	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
305c6fd2807SJeff Garzik };
306c6fd2807SJeff Garzik 
307c6fd2807SJeff Garzik enum chip_type {
308c6fd2807SJeff Garzik 	chip_504x,
309c6fd2807SJeff Garzik 	chip_508x,
310c6fd2807SJeff Garzik 	chip_5080,
311c6fd2807SJeff Garzik 	chip_604x,
312c6fd2807SJeff Garzik 	chip_608x,
313c6fd2807SJeff Garzik 	chip_6042,
314c6fd2807SJeff Garzik 	chip_7042,
315c6fd2807SJeff Garzik };
316c6fd2807SJeff Garzik 
317c6fd2807SJeff Garzik /* Command ReQuest Block: 32B */
318c6fd2807SJeff Garzik struct mv_crqb {
319c6fd2807SJeff Garzik 	__le32			sg_addr;
320c6fd2807SJeff Garzik 	__le32			sg_addr_hi;
321c6fd2807SJeff Garzik 	__le16			ctrl_flags;
322c6fd2807SJeff Garzik 	__le16			ata_cmd[11];
323c6fd2807SJeff Garzik };
324c6fd2807SJeff Garzik 
325c6fd2807SJeff Garzik struct mv_crqb_iie {
326c6fd2807SJeff Garzik 	__le32			addr;
327c6fd2807SJeff Garzik 	__le32			addr_hi;
328c6fd2807SJeff Garzik 	__le32			flags;
329c6fd2807SJeff Garzik 	__le32			len;
330c6fd2807SJeff Garzik 	__le32			ata_cmd[4];
331c6fd2807SJeff Garzik };
332c6fd2807SJeff Garzik 
333c6fd2807SJeff Garzik /* Command ResPonse Block: 8B */
334c6fd2807SJeff Garzik struct mv_crpb {
335c6fd2807SJeff Garzik 	__le16			id;
336c6fd2807SJeff Garzik 	__le16			flags;
337c6fd2807SJeff Garzik 	__le32			tmstmp;
338c6fd2807SJeff Garzik };
339c6fd2807SJeff Garzik 
340c6fd2807SJeff Garzik /* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
341c6fd2807SJeff Garzik struct mv_sg {
342c6fd2807SJeff Garzik 	__le32			addr;
343c6fd2807SJeff Garzik 	__le32			flags_size;
344c6fd2807SJeff Garzik 	__le32			addr_hi;
345c6fd2807SJeff Garzik 	__le32			reserved;
346c6fd2807SJeff Garzik };
347c6fd2807SJeff Garzik 
348c6fd2807SJeff Garzik struct mv_port_priv {
349c6fd2807SJeff Garzik 	struct mv_crqb		*crqb;
350c6fd2807SJeff Garzik 	dma_addr_t		crqb_dma;
351c6fd2807SJeff Garzik 	struct mv_crpb		*crpb;
352c6fd2807SJeff Garzik 	dma_addr_t		crpb_dma;
353c6fd2807SJeff Garzik 	struct mv_sg		*sg_tbl;
354c6fd2807SJeff Garzik 	dma_addr_t		sg_tbl_dma;
355c6fd2807SJeff Garzik 	u32			pp_flags;
356c6fd2807SJeff Garzik };
357c6fd2807SJeff Garzik 
358c6fd2807SJeff Garzik struct mv_port_signal {
359c6fd2807SJeff Garzik 	u32			amps;
360c6fd2807SJeff Garzik 	u32			pre;
361c6fd2807SJeff Garzik };
362c6fd2807SJeff Garzik 
363c6fd2807SJeff Garzik struct mv_host_priv;
364c6fd2807SJeff Garzik struct mv_hw_ops {
365c6fd2807SJeff Garzik 	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
366c6fd2807SJeff Garzik 			   unsigned int port);
367c6fd2807SJeff Garzik 	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
368c6fd2807SJeff Garzik 	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
369c6fd2807SJeff Garzik 			   void __iomem *mmio);
370c6fd2807SJeff Garzik 	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
371c6fd2807SJeff Garzik 			unsigned int n_hc);
372c6fd2807SJeff Garzik 	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
373c6fd2807SJeff Garzik 	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
374c6fd2807SJeff Garzik };
375c6fd2807SJeff Garzik 
376c6fd2807SJeff Garzik struct mv_host_priv {
377c6fd2807SJeff Garzik 	u32			hp_flags;
378c6fd2807SJeff Garzik 	struct mv_port_signal	signal[8];
379c6fd2807SJeff Garzik 	const struct mv_hw_ops	*ops;
380c6fd2807SJeff Garzik };
381c6fd2807SJeff Garzik 
382c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap);
383c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
384c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
385c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
386c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
387c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap);
388c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
389c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap);
390c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap);
391c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc);
392c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
393c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
394c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap);
395c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
396c6fd2807SJeff Garzik 
397c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
398c6fd2807SJeff Garzik 			   unsigned int port);
399c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
400c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
401c6fd2807SJeff Garzik 			   void __iomem *mmio);
402c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
403c6fd2807SJeff Garzik 			unsigned int n_hc);
404c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
405c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
406c6fd2807SJeff Garzik 
407c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
408c6fd2807SJeff Garzik 			   unsigned int port);
409c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
410c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
411c6fd2807SJeff Garzik 			   void __iomem *mmio);
412c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
413c6fd2807SJeff Garzik 			unsigned int n_hc);
414c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
415c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
416c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
417c6fd2807SJeff Garzik 			     unsigned int port_no);
418c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap);
419c6fd2807SJeff Garzik 
420c6fd2807SJeff Garzik static struct scsi_host_template mv_sht = {
421c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
422c6fd2807SJeff Garzik 	.name			= DRV_NAME,
423c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
424c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
425c6fd2807SJeff Garzik 	.can_queue		= MV_USE_Q_DEPTH,
426c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
427d88184fbSJeff Garzik 	.sg_tablesize		= MV_MAX_SG_CT,
428c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
429c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
430d88184fbSJeff Garzik 	.use_clustering		= 1,
431c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
432c6fd2807SJeff Garzik 	.dma_boundary		= MV_DMA_BOUNDARY,
433c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
434c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
435c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
436c6fd2807SJeff Garzik };
437c6fd2807SJeff Garzik 
438c6fd2807SJeff Garzik static const struct ata_port_operations mv5_ops = {
439c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
440c6fd2807SJeff Garzik 
441c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
442c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
443c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
444c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
445c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
446c6fd2807SJeff Garzik 
447c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
448cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
449c6fd2807SJeff Garzik 
450c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep,
451c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
4520d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
453c6fd2807SJeff Garzik 
454c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
455c6fd2807SJeff Garzik 
456c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
457246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
458246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
459c6fd2807SJeff Garzik 
460c6fd2807SJeff Garzik 	.scr_read		= mv5_scr_read,
461c6fd2807SJeff Garzik 	.scr_write		= mv5_scr_write,
462c6fd2807SJeff Garzik 
463c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
464c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
465c6fd2807SJeff Garzik };
466c6fd2807SJeff Garzik 
467c6fd2807SJeff Garzik static const struct ata_port_operations mv6_ops = {
468c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
469c6fd2807SJeff Garzik 
470c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
471c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
472c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
473c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
474c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
475c6fd2807SJeff Garzik 
476c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
477cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
478c6fd2807SJeff Garzik 
479c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep,
480c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
4810d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
482c6fd2807SJeff Garzik 
483c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
484c6fd2807SJeff Garzik 
485c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
486246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
487246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
488c6fd2807SJeff Garzik 
489c6fd2807SJeff Garzik 	.scr_read		= mv_scr_read,
490c6fd2807SJeff Garzik 	.scr_write		= mv_scr_write,
491c6fd2807SJeff Garzik 
492c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
493c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
494c6fd2807SJeff Garzik };
495c6fd2807SJeff Garzik 
496c6fd2807SJeff Garzik static const struct ata_port_operations mv_iie_ops = {
497c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
498c6fd2807SJeff Garzik 
499c6fd2807SJeff Garzik 	.tf_load		= ata_tf_load,
500c6fd2807SJeff Garzik 	.tf_read		= ata_tf_read,
501c6fd2807SJeff Garzik 	.check_status		= ata_check_status,
502c6fd2807SJeff Garzik 	.exec_command		= ata_exec_command,
503c6fd2807SJeff Garzik 	.dev_select		= ata_std_dev_select,
504c6fd2807SJeff Garzik 
505c6fd2807SJeff Garzik 	.phy_reset		= mv_phy_reset,
506cffacd85SJeff Garzik 	.cable_detect		= ata_cable_sata,
507c6fd2807SJeff Garzik 
508c6fd2807SJeff Garzik 	.qc_prep		= mv_qc_prep_iie,
509c6fd2807SJeff Garzik 	.qc_issue		= mv_qc_issue,
5100d5ff566STejun Heo 	.data_xfer		= ata_data_xfer,
511c6fd2807SJeff Garzik 
512c6fd2807SJeff Garzik 	.eng_timeout		= mv_eng_timeout,
513c6fd2807SJeff Garzik 
514c6fd2807SJeff Garzik 	.irq_clear		= mv_irq_clear,
515246ce3b6SAkira Iguchi 	.irq_on			= ata_irq_on,
516246ce3b6SAkira Iguchi 	.irq_ack		= ata_irq_ack,
517c6fd2807SJeff Garzik 
518c6fd2807SJeff Garzik 	.scr_read		= mv_scr_read,
519c6fd2807SJeff Garzik 	.scr_write		= mv_scr_write,
520c6fd2807SJeff Garzik 
521c6fd2807SJeff Garzik 	.port_start		= mv_port_start,
522c6fd2807SJeff Garzik 	.port_stop		= mv_port_stop,
523c6fd2807SJeff Garzik };
524c6fd2807SJeff Garzik 
525c6fd2807SJeff Garzik static const struct ata_port_info mv_port_info[] = {
526c6fd2807SJeff Garzik 	{  /* chip_504x */
527cca3974eSJeff Garzik 		.flags		= MV_COMMON_FLAGS,
528c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
529c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
530c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
531c6fd2807SJeff Garzik 	},
532c6fd2807SJeff Garzik 	{  /* chip_508x */
533cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
534c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
535c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
536c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
537c6fd2807SJeff Garzik 	},
538c6fd2807SJeff Garzik 	{  /* chip_5080 */
539cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
540c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
541c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
542c6fd2807SJeff Garzik 		.port_ops	= &mv5_ops,
543c6fd2807SJeff Garzik 	},
544c6fd2807SJeff Garzik 	{  /* chip_604x */
545cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
546c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
547c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
548c6fd2807SJeff Garzik 		.port_ops	= &mv6_ops,
549c6fd2807SJeff Garzik 	},
550c6fd2807SJeff Garzik 	{  /* chip_608x */
551cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
552c6fd2807SJeff Garzik 				   MV_FLAG_DUAL_HC),
553c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
554c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
555c6fd2807SJeff Garzik 		.port_ops	= &mv6_ops,
556c6fd2807SJeff Garzik 	},
557c6fd2807SJeff Garzik 	{  /* chip_6042 */
558cca3974eSJeff Garzik 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
559c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
560c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
561c6fd2807SJeff Garzik 		.port_ops	= &mv_iie_ops,
562c6fd2807SJeff Garzik 	},
563c6fd2807SJeff Garzik 	{  /* chip_7042 */
564e93f09dcSOlof Johansson 		.flags		= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
565c6fd2807SJeff Garzik 		.pio_mask	= 0x1f,	/* pio0-4 */
566c6fd2807SJeff Garzik 		.udma_mask	= 0x7f,	/* udma0-6 */
567c6fd2807SJeff Garzik 		.port_ops	= &mv_iie_ops,
568c6fd2807SJeff Garzik 	},
569c6fd2807SJeff Garzik };
570c6fd2807SJeff Garzik 
571c6fd2807SJeff Garzik static const struct pci_device_id mv_pci_tbl[] = {
5722d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
5732d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
5742d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
5752d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
576c6fd2807SJeff Garzik 
5772d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
5782d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
5792d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
5802d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
5812d2744fcSJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
582c6fd2807SJeff Garzik 
5832d2744fcSJeff Garzik 	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
5842d2744fcSJeff Garzik 
585e93f09dcSOlof Johansson 	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
586e93f09dcSOlof Johansson 
5876a3d586dSMorrison, Tom 	/* add Marvell 7042 support */
5886a3d586dSMorrison, Tom 	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
5896a3d586dSMorrison, Tom 
590c6fd2807SJeff Garzik 	{ }			/* terminate list */
591c6fd2807SJeff Garzik };
592c6fd2807SJeff Garzik 
593c6fd2807SJeff Garzik static struct pci_driver mv_pci_driver = {
594c6fd2807SJeff Garzik 	.name			= DRV_NAME,
595c6fd2807SJeff Garzik 	.id_table		= mv_pci_tbl,
596c6fd2807SJeff Garzik 	.probe			= mv_init_one,
597c6fd2807SJeff Garzik 	.remove			= ata_pci_remove_one,
598c6fd2807SJeff Garzik };
599c6fd2807SJeff Garzik 
600c6fd2807SJeff Garzik static const struct mv_hw_ops mv5xxx_ops = {
601c6fd2807SJeff Garzik 	.phy_errata		= mv5_phy_errata,
602c6fd2807SJeff Garzik 	.enable_leds		= mv5_enable_leds,
603c6fd2807SJeff Garzik 	.read_preamp		= mv5_read_preamp,
604c6fd2807SJeff Garzik 	.reset_hc		= mv5_reset_hc,
605c6fd2807SJeff Garzik 	.reset_flash		= mv5_reset_flash,
606c6fd2807SJeff Garzik 	.reset_bus		= mv5_reset_bus,
607c6fd2807SJeff Garzik };
608c6fd2807SJeff Garzik 
609c6fd2807SJeff Garzik static const struct mv_hw_ops mv6xxx_ops = {
610c6fd2807SJeff Garzik 	.phy_errata		= mv6_phy_errata,
611c6fd2807SJeff Garzik 	.enable_leds		= mv6_enable_leds,
612c6fd2807SJeff Garzik 	.read_preamp		= mv6_read_preamp,
613c6fd2807SJeff Garzik 	.reset_hc		= mv6_reset_hc,
614c6fd2807SJeff Garzik 	.reset_flash		= mv6_reset_flash,
615c6fd2807SJeff Garzik 	.reset_bus		= mv_reset_pci_bus,
616c6fd2807SJeff Garzik };
617c6fd2807SJeff Garzik 
618c6fd2807SJeff Garzik /*
619c6fd2807SJeff Garzik  * module options
620c6fd2807SJeff Garzik  */
621c6fd2807SJeff Garzik static int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
622c6fd2807SJeff Garzik 
623c6fd2807SJeff Garzik 
624d88184fbSJeff Garzik /* move to PCI layer or libata core? */
625d88184fbSJeff Garzik static int pci_go_64(struct pci_dev *pdev)
626d88184fbSJeff Garzik {
627d88184fbSJeff Garzik 	int rc;
628d88184fbSJeff Garzik 
629d88184fbSJeff Garzik 	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
630d88184fbSJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
631d88184fbSJeff Garzik 		if (rc) {
632d88184fbSJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
633d88184fbSJeff Garzik 			if (rc) {
634d88184fbSJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
635d88184fbSJeff Garzik 					   "64-bit DMA enable failed\n");
636d88184fbSJeff Garzik 				return rc;
637d88184fbSJeff Garzik 			}
638d88184fbSJeff Garzik 		}
639d88184fbSJeff Garzik 	} else {
640d88184fbSJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
641d88184fbSJeff Garzik 		if (rc) {
642d88184fbSJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
643d88184fbSJeff Garzik 				   "32-bit DMA enable failed\n");
644d88184fbSJeff Garzik 			return rc;
645d88184fbSJeff Garzik 		}
646d88184fbSJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
647d88184fbSJeff Garzik 		if (rc) {
648d88184fbSJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
649d88184fbSJeff Garzik 				   "32-bit consistent DMA enable failed\n");
650d88184fbSJeff Garzik 			return rc;
651d88184fbSJeff Garzik 		}
652d88184fbSJeff Garzik 	}
653d88184fbSJeff Garzik 
654d88184fbSJeff Garzik 	return rc;
655d88184fbSJeff Garzik }
656d88184fbSJeff Garzik 
657c6fd2807SJeff Garzik /*
658c6fd2807SJeff Garzik  * Functions
659c6fd2807SJeff Garzik  */
660c6fd2807SJeff Garzik 
661c6fd2807SJeff Garzik static inline void writelfl(unsigned long data, void __iomem *addr)
662c6fd2807SJeff Garzik {
663c6fd2807SJeff Garzik 	writel(data, addr);
664c6fd2807SJeff Garzik 	(void) readl(addr);	/* flush to avoid PCI posted write */
665c6fd2807SJeff Garzik }
666c6fd2807SJeff Garzik 
667c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
668c6fd2807SJeff Garzik {
669c6fd2807SJeff Garzik 	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
670c6fd2807SJeff Garzik }
671c6fd2807SJeff Garzik 
672c6fd2807SJeff Garzik static inline unsigned int mv_hc_from_port(unsigned int port)
673c6fd2807SJeff Garzik {
674c6fd2807SJeff Garzik 	return port >> MV_PORT_HC_SHIFT;
675c6fd2807SJeff Garzik }
676c6fd2807SJeff Garzik 
677c6fd2807SJeff Garzik static inline unsigned int mv_hardport_from_port(unsigned int port)
678c6fd2807SJeff Garzik {
679c6fd2807SJeff Garzik 	return port & MV_PORT_MASK;
680c6fd2807SJeff Garzik }
681c6fd2807SJeff Garzik 
682c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
683c6fd2807SJeff Garzik 						 unsigned int port)
684c6fd2807SJeff Garzik {
685c6fd2807SJeff Garzik 	return mv_hc_base(base, mv_hc_from_port(port));
686c6fd2807SJeff Garzik }
687c6fd2807SJeff Garzik 
688c6fd2807SJeff Garzik static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
689c6fd2807SJeff Garzik {
690c6fd2807SJeff Garzik 	return  mv_hc_base_from_port(base, port) +
691c6fd2807SJeff Garzik 		MV_SATAHC_ARBTR_REG_SZ +
692c6fd2807SJeff Garzik 		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
693c6fd2807SJeff Garzik }
694c6fd2807SJeff Garzik 
695c6fd2807SJeff Garzik static inline void __iomem *mv_ap_base(struct ata_port *ap)
696c6fd2807SJeff Garzik {
6970d5ff566STejun Heo 	return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
698c6fd2807SJeff Garzik }
699c6fd2807SJeff Garzik 
700cca3974eSJeff Garzik static inline int mv_get_hc_count(unsigned long port_flags)
701c6fd2807SJeff Garzik {
702cca3974eSJeff Garzik 	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
703c6fd2807SJeff Garzik }
704c6fd2807SJeff Garzik 
705c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap)
706c6fd2807SJeff Garzik {
707c6fd2807SJeff Garzik }
708c6fd2807SJeff Garzik 
709c6fd2807SJeff Garzik /**
710c6fd2807SJeff Garzik  *      mv_start_dma - Enable eDMA engine
711c6fd2807SJeff Garzik  *      @base: port base address
712c6fd2807SJeff Garzik  *      @pp: port private data
713c6fd2807SJeff Garzik  *
714c6fd2807SJeff Garzik  *      Verify the local cache of the eDMA state is accurate with a
715c6fd2807SJeff Garzik  *      WARN_ON.
716c6fd2807SJeff Garzik  *
717c6fd2807SJeff Garzik  *      LOCKING:
718c6fd2807SJeff Garzik  *      Inherited from caller.
719c6fd2807SJeff Garzik  */
720c6fd2807SJeff Garzik static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
721c6fd2807SJeff Garzik {
722c6fd2807SJeff Garzik 	if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
723c6fd2807SJeff Garzik 		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
724c6fd2807SJeff Garzik 		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
725c6fd2807SJeff Garzik 	}
726c6fd2807SJeff Garzik 	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
727c6fd2807SJeff Garzik }
728c6fd2807SJeff Garzik 
729c6fd2807SJeff Garzik /**
730c6fd2807SJeff Garzik  *      mv_stop_dma - Disable eDMA engine
731c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
732c6fd2807SJeff Garzik  *
733c6fd2807SJeff Garzik  *      Verify the local cache of the eDMA state is accurate with a
734c6fd2807SJeff Garzik  *      WARN_ON.
735c6fd2807SJeff Garzik  *
736c6fd2807SJeff Garzik  *      LOCKING:
737c6fd2807SJeff Garzik  *      Inherited from caller.
738c6fd2807SJeff Garzik  */
739c6fd2807SJeff Garzik static void mv_stop_dma(struct ata_port *ap)
740c6fd2807SJeff Garzik {
741c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
742c6fd2807SJeff Garzik 	struct mv_port_priv *pp	= ap->private_data;
743c6fd2807SJeff Garzik 	u32 reg;
744c6fd2807SJeff Garzik 	int i;
745c6fd2807SJeff Garzik 
746c6fd2807SJeff Garzik 	if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
747c6fd2807SJeff Garzik 		/* Disable EDMA if active.   The disable bit auto clears.
748c6fd2807SJeff Garzik 		 */
749c6fd2807SJeff Garzik 		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
750c6fd2807SJeff Garzik 		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
751c6fd2807SJeff Garzik 	} else {
752c6fd2807SJeff Garzik 		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
753c6fd2807SJeff Garzik   	}
754c6fd2807SJeff Garzik 
755c6fd2807SJeff Garzik 	/* now properly wait for the eDMA to stop */
756c6fd2807SJeff Garzik 	for (i = 1000; i > 0; i--) {
757c6fd2807SJeff Garzik 		reg = readl(port_mmio + EDMA_CMD_OFS);
758c6fd2807SJeff Garzik 		if (!(EDMA_EN & reg)) {
759c6fd2807SJeff Garzik 			break;
760c6fd2807SJeff Garzik 		}
761c6fd2807SJeff Garzik 		udelay(100);
762c6fd2807SJeff Garzik 	}
763c6fd2807SJeff Garzik 
764c6fd2807SJeff Garzik 	if (EDMA_EN & reg) {
765c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
766c6fd2807SJeff Garzik 		/* FIXME: Consider doing a reset here to recover */
767c6fd2807SJeff Garzik 	}
768c6fd2807SJeff Garzik }
769c6fd2807SJeff Garzik 
770c6fd2807SJeff Garzik #ifdef ATA_DEBUG
771c6fd2807SJeff Garzik static void mv_dump_mem(void __iomem *start, unsigned bytes)
772c6fd2807SJeff Garzik {
773c6fd2807SJeff Garzik 	int b, w;
774c6fd2807SJeff Garzik 	for (b = 0; b < bytes; ) {
775c6fd2807SJeff Garzik 		DPRINTK("%p: ", start + b);
776c6fd2807SJeff Garzik 		for (w = 0; b < bytes && w < 4; w++) {
777c6fd2807SJeff Garzik 			printk("%08x ",readl(start + b));
778c6fd2807SJeff Garzik 			b += sizeof(u32);
779c6fd2807SJeff Garzik 		}
780c6fd2807SJeff Garzik 		printk("\n");
781c6fd2807SJeff Garzik 	}
782c6fd2807SJeff Garzik }
783c6fd2807SJeff Garzik #endif
784c6fd2807SJeff Garzik 
785c6fd2807SJeff Garzik static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
786c6fd2807SJeff Garzik {
787c6fd2807SJeff Garzik #ifdef ATA_DEBUG
788c6fd2807SJeff Garzik 	int b, w;
789c6fd2807SJeff Garzik 	u32 dw;
790c6fd2807SJeff Garzik 	for (b = 0; b < bytes; ) {
791c6fd2807SJeff Garzik 		DPRINTK("%02x: ", b);
792c6fd2807SJeff Garzik 		for (w = 0; b < bytes && w < 4; w++) {
793c6fd2807SJeff Garzik 			(void) pci_read_config_dword(pdev,b,&dw);
794c6fd2807SJeff Garzik 			printk("%08x ",dw);
795c6fd2807SJeff Garzik 			b += sizeof(u32);
796c6fd2807SJeff Garzik 		}
797c6fd2807SJeff Garzik 		printk("\n");
798c6fd2807SJeff Garzik 	}
799c6fd2807SJeff Garzik #endif
800c6fd2807SJeff Garzik }
801c6fd2807SJeff Garzik static void mv_dump_all_regs(void __iomem *mmio_base, int port,
802c6fd2807SJeff Garzik 			     struct pci_dev *pdev)
803c6fd2807SJeff Garzik {
804c6fd2807SJeff Garzik #ifdef ATA_DEBUG
805c6fd2807SJeff Garzik 	void __iomem *hc_base = mv_hc_base(mmio_base,
806c6fd2807SJeff Garzik 					   port >> MV_PORT_HC_SHIFT);
807c6fd2807SJeff Garzik 	void __iomem *port_base;
808c6fd2807SJeff Garzik 	int start_port, num_ports, p, start_hc, num_hcs, hc;
809c6fd2807SJeff Garzik 
810c6fd2807SJeff Garzik 	if (0 > port) {
811c6fd2807SJeff Garzik 		start_hc = start_port = 0;
812c6fd2807SJeff Garzik 		num_ports = 8;		/* shld be benign for 4 port devs */
813c6fd2807SJeff Garzik 		num_hcs = 2;
814c6fd2807SJeff Garzik 	} else {
815c6fd2807SJeff Garzik 		start_hc = port >> MV_PORT_HC_SHIFT;
816c6fd2807SJeff Garzik 		start_port = port;
817c6fd2807SJeff Garzik 		num_ports = num_hcs = 1;
818c6fd2807SJeff Garzik 	}
819c6fd2807SJeff Garzik 	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
820c6fd2807SJeff Garzik 		num_ports > 1 ? num_ports - 1 : start_port);
821c6fd2807SJeff Garzik 
822c6fd2807SJeff Garzik 	if (NULL != pdev) {
823c6fd2807SJeff Garzik 		DPRINTK("PCI config space regs:\n");
824c6fd2807SJeff Garzik 		mv_dump_pci_cfg(pdev, 0x68);
825c6fd2807SJeff Garzik 	}
826c6fd2807SJeff Garzik 	DPRINTK("PCI regs:\n");
827c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xc00, 0x3c);
828c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xd00, 0x34);
829c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0xf00, 0x4);
830c6fd2807SJeff Garzik 	mv_dump_mem(mmio_base+0x1d00, 0x6c);
831c6fd2807SJeff Garzik 	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
832c6fd2807SJeff Garzik 		hc_base = mv_hc_base(mmio_base, hc);
833c6fd2807SJeff Garzik 		DPRINTK("HC regs (HC %i):\n", hc);
834c6fd2807SJeff Garzik 		mv_dump_mem(hc_base, 0x1c);
835c6fd2807SJeff Garzik 	}
836c6fd2807SJeff Garzik 	for (p = start_port; p < start_port + num_ports; p++) {
837c6fd2807SJeff Garzik 		port_base = mv_port_base(mmio_base, p);
838c6fd2807SJeff Garzik 		DPRINTK("EDMA regs (port %i):\n",p);
839c6fd2807SJeff Garzik 		mv_dump_mem(port_base, 0x54);
840c6fd2807SJeff Garzik 		DPRINTK("SATA regs (port %i):\n",p);
841c6fd2807SJeff Garzik 		mv_dump_mem(port_base+0x300, 0x60);
842c6fd2807SJeff Garzik 	}
843c6fd2807SJeff Garzik #endif
844c6fd2807SJeff Garzik }
845c6fd2807SJeff Garzik 
846c6fd2807SJeff Garzik static unsigned int mv_scr_offset(unsigned int sc_reg_in)
847c6fd2807SJeff Garzik {
848c6fd2807SJeff Garzik 	unsigned int ofs;
849c6fd2807SJeff Garzik 
850c6fd2807SJeff Garzik 	switch (sc_reg_in) {
851c6fd2807SJeff Garzik 	case SCR_STATUS:
852c6fd2807SJeff Garzik 	case SCR_CONTROL:
853c6fd2807SJeff Garzik 	case SCR_ERROR:
854c6fd2807SJeff Garzik 		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
855c6fd2807SJeff Garzik 		break;
856c6fd2807SJeff Garzik 	case SCR_ACTIVE:
857c6fd2807SJeff Garzik 		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
858c6fd2807SJeff Garzik 		break;
859c6fd2807SJeff Garzik 	default:
860c6fd2807SJeff Garzik 		ofs = 0xffffffffU;
861c6fd2807SJeff Garzik 		break;
862c6fd2807SJeff Garzik 	}
863c6fd2807SJeff Garzik 	return ofs;
864c6fd2807SJeff Garzik }
865c6fd2807SJeff Garzik 
866c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
867c6fd2807SJeff Garzik {
868c6fd2807SJeff Garzik 	unsigned int ofs = mv_scr_offset(sc_reg_in);
869c6fd2807SJeff Garzik 
87035177265SJeff Garzik 	if (0xffffffffU != ofs)
871c6fd2807SJeff Garzik 		return readl(mv_ap_base(ap) + ofs);
87235177265SJeff Garzik 	else
873c6fd2807SJeff Garzik 		return (u32) ofs;
874c6fd2807SJeff Garzik }
875c6fd2807SJeff Garzik 
876c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
877c6fd2807SJeff Garzik {
878c6fd2807SJeff Garzik 	unsigned int ofs = mv_scr_offset(sc_reg_in);
879c6fd2807SJeff Garzik 
88035177265SJeff Garzik 	if (0xffffffffU != ofs)
881c6fd2807SJeff Garzik 		writelfl(val, mv_ap_base(ap) + ofs);
882c6fd2807SJeff Garzik }
883c6fd2807SJeff Garzik 
884c6fd2807SJeff Garzik static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
885c6fd2807SJeff Garzik {
886c6fd2807SJeff Garzik 	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
887c6fd2807SJeff Garzik 
888c6fd2807SJeff Garzik 	/* set up non-NCQ EDMA configuration */
889c6fd2807SJeff Garzik 	cfg &= ~(1 << 9);	/* disable equeue */
890c6fd2807SJeff Garzik 
891e728eabeSJeff Garzik 	if (IS_GEN_I(hpriv)) {
892e728eabeSJeff Garzik 		cfg &= ~0x1f;		/* clear queue depth */
893c6fd2807SJeff Garzik 		cfg |= (1 << 8);	/* enab config burst size mask */
894e728eabeSJeff Garzik 	}
895c6fd2807SJeff Garzik 
896e728eabeSJeff Garzik 	else if (IS_GEN_II(hpriv)) {
897e728eabeSJeff Garzik 		cfg &= ~0x1f;		/* clear queue depth */
898c6fd2807SJeff Garzik 		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
899e728eabeSJeff Garzik 		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
900e728eabeSJeff Garzik 	}
901c6fd2807SJeff Garzik 
902c6fd2807SJeff Garzik 	else if (IS_GEN_IIE(hpriv)) {
903e728eabeSJeff Garzik 		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
904e728eabeSJeff Garzik 		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
905c6fd2807SJeff Garzik 		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
906c6fd2807SJeff Garzik 		cfg |= (1 << 18);	/* enab early completion */
907e728eabeSJeff Garzik 		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
908e728eabeSJeff Garzik 		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
909e728eabeSJeff Garzik 		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
910c6fd2807SJeff Garzik 	}
911c6fd2807SJeff Garzik 
912c6fd2807SJeff Garzik 	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
913c6fd2807SJeff Garzik }
914c6fd2807SJeff Garzik 
915c6fd2807SJeff Garzik /**
916c6fd2807SJeff Garzik  *      mv_port_start - Port specific init/start routine.
917c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
918c6fd2807SJeff Garzik  *
919c6fd2807SJeff Garzik  *      Allocate and point to DMA memory, init port private memory,
920c6fd2807SJeff Garzik  *      zero indices.
921c6fd2807SJeff Garzik  *
922c6fd2807SJeff Garzik  *      LOCKING:
923c6fd2807SJeff Garzik  *      Inherited from caller.
924c6fd2807SJeff Garzik  */
925c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap)
926c6fd2807SJeff Garzik {
927cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
928cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
929c6fd2807SJeff Garzik 	struct mv_port_priv *pp;
930c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
931c6fd2807SJeff Garzik 	void *mem;
932c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
93324dc5f33STejun Heo 	int rc;
934c6fd2807SJeff Garzik 
93524dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
936c6fd2807SJeff Garzik 	if (!pp)
93724dc5f33STejun Heo 		return -ENOMEM;
938c6fd2807SJeff Garzik 
93924dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
940c6fd2807SJeff Garzik 				  GFP_KERNEL);
941c6fd2807SJeff Garzik 	if (!mem)
94224dc5f33STejun Heo 		return -ENOMEM;
943c6fd2807SJeff Garzik 	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
944c6fd2807SJeff Garzik 
945c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
946c6fd2807SJeff Garzik 	if (rc)
94724dc5f33STejun Heo 		return rc;
948c6fd2807SJeff Garzik 
949c6fd2807SJeff Garzik 	/* First item in chunk of DMA memory:
950c6fd2807SJeff Garzik 	 * 32-slot command request table (CRQB), 32 bytes each in size
951c6fd2807SJeff Garzik 	 */
952c6fd2807SJeff Garzik 	pp->crqb = mem;
953c6fd2807SJeff Garzik 	pp->crqb_dma = mem_dma;
954c6fd2807SJeff Garzik 	mem += MV_CRQB_Q_SZ;
955c6fd2807SJeff Garzik 	mem_dma += MV_CRQB_Q_SZ;
956c6fd2807SJeff Garzik 
957c6fd2807SJeff Garzik 	/* Second item:
958c6fd2807SJeff Garzik 	 * 32-slot command response table (CRPB), 8 bytes each in size
959c6fd2807SJeff Garzik 	 */
960c6fd2807SJeff Garzik 	pp->crpb = mem;
961c6fd2807SJeff Garzik 	pp->crpb_dma = mem_dma;
962c6fd2807SJeff Garzik 	mem += MV_CRPB_Q_SZ;
963c6fd2807SJeff Garzik 	mem_dma += MV_CRPB_Q_SZ;
964c6fd2807SJeff Garzik 
965c6fd2807SJeff Garzik 	/* Third item:
966c6fd2807SJeff Garzik 	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
967c6fd2807SJeff Garzik 	 */
968c6fd2807SJeff Garzik 	pp->sg_tbl = mem;
969c6fd2807SJeff Garzik 	pp->sg_tbl_dma = mem_dma;
970c6fd2807SJeff Garzik 
971c6fd2807SJeff Garzik 	mv_edma_cfg(hpriv, port_mmio);
972c6fd2807SJeff Garzik 
973c6fd2807SJeff Garzik 	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
974c6fd2807SJeff Garzik 	writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
975c6fd2807SJeff Garzik 		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
976c6fd2807SJeff Garzik 
977c6fd2807SJeff Garzik 	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
978c6fd2807SJeff Garzik 		writelfl(pp->crqb_dma & 0xffffffff,
979c6fd2807SJeff Garzik 			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
980c6fd2807SJeff Garzik 	else
981c6fd2807SJeff Garzik 		writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
982c6fd2807SJeff Garzik 
983c6fd2807SJeff Garzik 	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
984c6fd2807SJeff Garzik 
985c6fd2807SJeff Garzik 	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
986c6fd2807SJeff Garzik 		writelfl(pp->crpb_dma & 0xffffffff,
987c6fd2807SJeff Garzik 			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
988c6fd2807SJeff Garzik 	else
989c6fd2807SJeff Garzik 		writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
990c6fd2807SJeff Garzik 
991c6fd2807SJeff Garzik 	writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
992c6fd2807SJeff Garzik 		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
993c6fd2807SJeff Garzik 
994c6fd2807SJeff Garzik 	/* Don't turn on EDMA here...do it before DMA commands only.  Else
995c6fd2807SJeff Garzik 	 * we'll be unable to send non-data, PIO, etc due to restricted access
996c6fd2807SJeff Garzik 	 * to shadow regs.
997c6fd2807SJeff Garzik 	 */
998c6fd2807SJeff Garzik 	ap->private_data = pp;
999c6fd2807SJeff Garzik 	return 0;
1000c6fd2807SJeff Garzik }
1001c6fd2807SJeff Garzik 
1002c6fd2807SJeff Garzik /**
1003c6fd2807SJeff Garzik  *      mv_port_stop - Port specific cleanup/stop routine.
1004c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1005c6fd2807SJeff Garzik  *
1006c6fd2807SJeff Garzik  *      Stop DMA, cleanup port memory.
1007c6fd2807SJeff Garzik  *
1008c6fd2807SJeff Garzik  *      LOCKING:
1009cca3974eSJeff Garzik  *      This routine uses the host lock to protect the DMA stop.
1010c6fd2807SJeff Garzik  */
1011c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap)
1012c6fd2807SJeff Garzik {
1013c6fd2807SJeff Garzik 	unsigned long flags;
1014c6fd2807SJeff Garzik 
1015cca3974eSJeff Garzik 	spin_lock_irqsave(&ap->host->lock, flags);
1016c6fd2807SJeff Garzik 	mv_stop_dma(ap);
1017cca3974eSJeff Garzik 	spin_unlock_irqrestore(&ap->host->lock, flags);
1018c6fd2807SJeff Garzik }
1019c6fd2807SJeff Garzik 
1020c6fd2807SJeff Garzik /**
1021c6fd2807SJeff Garzik  *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
1022c6fd2807SJeff Garzik  *      @qc: queued command whose SG list to source from
1023c6fd2807SJeff Garzik  *
1024c6fd2807SJeff Garzik  *      Populate the SG list and mark the last entry.
1025c6fd2807SJeff Garzik  *
1026c6fd2807SJeff Garzik  *      LOCKING:
1027c6fd2807SJeff Garzik  *      Inherited from caller.
1028c6fd2807SJeff Garzik  */
1029d88184fbSJeff Garzik static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
1030c6fd2807SJeff Garzik {
1031c6fd2807SJeff Garzik 	struct mv_port_priv *pp = qc->ap->private_data;
1032d88184fbSJeff Garzik 	unsigned int n_sg = 0;
1033c6fd2807SJeff Garzik 	struct scatterlist *sg;
1034d88184fbSJeff Garzik 	struct mv_sg *mv_sg;
1035c6fd2807SJeff Garzik 
1036d88184fbSJeff Garzik 	mv_sg = pp->sg_tbl;
1037c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
1038d88184fbSJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1039d88184fbSJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1040c6fd2807SJeff Garzik 
1041d88184fbSJeff Garzik 		mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
1042d88184fbSJeff Garzik 		mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1043d88184fbSJeff Garzik 		mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
1044c6fd2807SJeff Garzik 
1045d88184fbSJeff Garzik 		if (ata_sg_is_last(sg, qc))
1046d88184fbSJeff Garzik 			mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
1047c6fd2807SJeff Garzik 
1048d88184fbSJeff Garzik 		mv_sg++;
1049d88184fbSJeff Garzik 		n_sg++;
1050c6fd2807SJeff Garzik 	}
1051d88184fbSJeff Garzik 
1052d88184fbSJeff Garzik 	return n_sg;
1053c6fd2807SJeff Garzik }
1054c6fd2807SJeff Garzik 
1055c6fd2807SJeff Garzik static inline unsigned mv_inc_q_index(unsigned index)
1056c6fd2807SJeff Garzik {
1057c6fd2807SJeff Garzik 	return (index + 1) & MV_MAX_Q_DEPTH_MASK;
1058c6fd2807SJeff Garzik }
1059c6fd2807SJeff Garzik 
1060c6fd2807SJeff Garzik static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
1061c6fd2807SJeff Garzik {
1062c6fd2807SJeff Garzik 	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
1063c6fd2807SJeff Garzik 		(last ? CRQB_CMD_LAST : 0);
1064c6fd2807SJeff Garzik 	*cmdw = cpu_to_le16(tmp);
1065c6fd2807SJeff Garzik }
1066c6fd2807SJeff Garzik 
1067c6fd2807SJeff Garzik /**
1068c6fd2807SJeff Garzik  *      mv_qc_prep - Host specific command preparation.
1069c6fd2807SJeff Garzik  *      @qc: queued command to prepare
1070c6fd2807SJeff Garzik  *
1071c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1072c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it handles prep of the CRQB
1073c6fd2807SJeff Garzik  *      (command request block), does some sanity checking, and calls
1074c6fd2807SJeff Garzik  *      the SG load routine.
1075c6fd2807SJeff Garzik  *
1076c6fd2807SJeff Garzik  *      LOCKING:
1077c6fd2807SJeff Garzik  *      Inherited from caller.
1078c6fd2807SJeff Garzik  */
1079c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc)
1080c6fd2807SJeff Garzik {
1081c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1082c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1083c6fd2807SJeff Garzik 	__le16 *cw;
1084c6fd2807SJeff Garzik 	struct ata_taskfile *tf;
1085c6fd2807SJeff Garzik 	u16 flags = 0;
1086c6fd2807SJeff Garzik 	unsigned in_index;
1087c6fd2807SJeff Garzik 
1088c6fd2807SJeff Garzik  	if (ATA_PROT_DMA != qc->tf.protocol)
1089c6fd2807SJeff Garzik 		return;
1090c6fd2807SJeff Garzik 
1091c6fd2807SJeff Garzik 	/* Fill in command request block
1092c6fd2807SJeff Garzik 	 */
1093c6fd2807SJeff Garzik 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1094c6fd2807SJeff Garzik 		flags |= CRQB_FLAG_READ;
1095c6fd2807SJeff Garzik 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1096c6fd2807SJeff Garzik 	flags |= qc->tag << CRQB_TAG_SHIFT;
1097c6fd2807SJeff Garzik 
1098c6fd2807SJeff Garzik 	/* get current queue index from hardware */
1099c6fd2807SJeff Garzik 	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
1100c6fd2807SJeff Garzik 			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1101c6fd2807SJeff Garzik 
1102c6fd2807SJeff Garzik 	pp->crqb[in_index].sg_addr =
1103c6fd2807SJeff Garzik 		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1104c6fd2807SJeff Garzik 	pp->crqb[in_index].sg_addr_hi =
1105c6fd2807SJeff Garzik 		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1106c6fd2807SJeff Garzik 	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
1107c6fd2807SJeff Garzik 
1108c6fd2807SJeff Garzik 	cw = &pp->crqb[in_index].ata_cmd[0];
1109c6fd2807SJeff Garzik 	tf = &qc->tf;
1110c6fd2807SJeff Garzik 
1111c6fd2807SJeff Garzik 	/* Sadly, the CRQB cannot accomodate all registers--there are
1112c6fd2807SJeff Garzik 	 * only 11 bytes...so we must pick and choose required
1113c6fd2807SJeff Garzik 	 * registers based on the command.  So, we drop feature and
1114c6fd2807SJeff Garzik 	 * hob_feature for [RW] DMA commands, but they are needed for
1115c6fd2807SJeff Garzik 	 * NCQ.  NCQ will drop hob_nsect.
1116c6fd2807SJeff Garzik 	 */
1117c6fd2807SJeff Garzik 	switch (tf->command) {
1118c6fd2807SJeff Garzik 	case ATA_CMD_READ:
1119c6fd2807SJeff Garzik 	case ATA_CMD_READ_EXT:
1120c6fd2807SJeff Garzik 	case ATA_CMD_WRITE:
1121c6fd2807SJeff Garzik 	case ATA_CMD_WRITE_EXT:
1122c6fd2807SJeff Garzik 	case ATA_CMD_WRITE_FUA_EXT:
1123c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
1124c6fd2807SJeff Garzik 		break;
1125c6fd2807SJeff Garzik #ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
1126c6fd2807SJeff Garzik 	case ATA_CMD_FPDMA_READ:
1127c6fd2807SJeff Garzik 	case ATA_CMD_FPDMA_WRITE:
1128c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
1129c6fd2807SJeff Garzik 		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
1130c6fd2807SJeff Garzik 		break;
1131c6fd2807SJeff Garzik #endif				/* FIXME: remove this line when NCQ added */
1132c6fd2807SJeff Garzik 	default:
1133c6fd2807SJeff Garzik 		/* The only other commands EDMA supports in non-queued and
1134c6fd2807SJeff Garzik 		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
1135c6fd2807SJeff Garzik 		 * of which are defined/used by Linux.  If we get here, this
1136c6fd2807SJeff Garzik 		 * driver needs work.
1137c6fd2807SJeff Garzik 		 *
1138c6fd2807SJeff Garzik 		 * FIXME: modify libata to give qc_prep a return value and
1139c6fd2807SJeff Garzik 		 * return error here.
1140c6fd2807SJeff Garzik 		 */
1141c6fd2807SJeff Garzik 		BUG_ON(tf->command);
1142c6fd2807SJeff Garzik 		break;
1143c6fd2807SJeff Garzik 	}
1144c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
1145c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
1146c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
1147c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
1148c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
1149c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
1150c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
1151c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
1152c6fd2807SJeff Garzik 	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
1153c6fd2807SJeff Garzik 
1154c6fd2807SJeff Garzik 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1155c6fd2807SJeff Garzik 		return;
1156c6fd2807SJeff Garzik 	mv_fill_sg(qc);
1157c6fd2807SJeff Garzik }
1158c6fd2807SJeff Garzik 
1159c6fd2807SJeff Garzik /**
1160c6fd2807SJeff Garzik  *      mv_qc_prep_iie - Host specific command preparation.
1161c6fd2807SJeff Garzik  *      @qc: queued command to prepare
1162c6fd2807SJeff Garzik  *
1163c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1164c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it handles prep of the CRQB
1165c6fd2807SJeff Garzik  *      (command request block), does some sanity checking, and calls
1166c6fd2807SJeff Garzik  *      the SG load routine.
1167c6fd2807SJeff Garzik  *
1168c6fd2807SJeff Garzik  *      LOCKING:
1169c6fd2807SJeff Garzik  *      Inherited from caller.
1170c6fd2807SJeff Garzik  */
1171c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1172c6fd2807SJeff Garzik {
1173c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1174c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1175c6fd2807SJeff Garzik 	struct mv_crqb_iie *crqb;
1176c6fd2807SJeff Garzik 	struct ata_taskfile *tf;
1177c6fd2807SJeff Garzik 	unsigned in_index;
1178c6fd2807SJeff Garzik 	u32 flags = 0;
1179c6fd2807SJeff Garzik 
1180c6fd2807SJeff Garzik  	if (ATA_PROT_DMA != qc->tf.protocol)
1181c6fd2807SJeff Garzik 		return;
1182c6fd2807SJeff Garzik 
1183c6fd2807SJeff Garzik 	/* Fill in Gen IIE command request block
1184c6fd2807SJeff Garzik 	 */
1185c6fd2807SJeff Garzik 	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1186c6fd2807SJeff Garzik 		flags |= CRQB_FLAG_READ;
1187c6fd2807SJeff Garzik 
1188c6fd2807SJeff Garzik 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1189c6fd2807SJeff Garzik 	flags |= qc->tag << CRQB_TAG_SHIFT;
1190c6fd2807SJeff Garzik 
1191c6fd2807SJeff Garzik 	/* get current queue index from hardware */
1192c6fd2807SJeff Garzik 	in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
1193c6fd2807SJeff Garzik 			>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1194c6fd2807SJeff Garzik 
1195c6fd2807SJeff Garzik 	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1196c6fd2807SJeff Garzik 	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1197c6fd2807SJeff Garzik 	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1198c6fd2807SJeff Garzik 	crqb->flags = cpu_to_le32(flags);
1199c6fd2807SJeff Garzik 
1200c6fd2807SJeff Garzik 	tf = &qc->tf;
1201c6fd2807SJeff Garzik 	crqb->ata_cmd[0] = cpu_to_le32(
1202c6fd2807SJeff Garzik 			(tf->command << 16) |
1203c6fd2807SJeff Garzik 			(tf->feature << 24)
1204c6fd2807SJeff Garzik 		);
1205c6fd2807SJeff Garzik 	crqb->ata_cmd[1] = cpu_to_le32(
1206c6fd2807SJeff Garzik 			(tf->lbal << 0) |
1207c6fd2807SJeff Garzik 			(tf->lbam << 8) |
1208c6fd2807SJeff Garzik 			(tf->lbah << 16) |
1209c6fd2807SJeff Garzik 			(tf->device << 24)
1210c6fd2807SJeff Garzik 		);
1211c6fd2807SJeff Garzik 	crqb->ata_cmd[2] = cpu_to_le32(
1212c6fd2807SJeff Garzik 			(tf->hob_lbal << 0) |
1213c6fd2807SJeff Garzik 			(tf->hob_lbam << 8) |
1214c6fd2807SJeff Garzik 			(tf->hob_lbah << 16) |
1215c6fd2807SJeff Garzik 			(tf->hob_feature << 24)
1216c6fd2807SJeff Garzik 		);
1217c6fd2807SJeff Garzik 	crqb->ata_cmd[3] = cpu_to_le32(
1218c6fd2807SJeff Garzik 			(tf->nsect << 0) |
1219c6fd2807SJeff Garzik 			(tf->hob_nsect << 8)
1220c6fd2807SJeff Garzik 		);
1221c6fd2807SJeff Garzik 
1222c6fd2807SJeff Garzik 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1223c6fd2807SJeff Garzik 		return;
1224c6fd2807SJeff Garzik 	mv_fill_sg(qc);
1225c6fd2807SJeff Garzik }
1226c6fd2807SJeff Garzik 
1227c6fd2807SJeff Garzik /**
1228c6fd2807SJeff Garzik  *      mv_qc_issue - Initiate a command to the host
1229c6fd2807SJeff Garzik  *      @qc: queued command to start
1230c6fd2807SJeff Garzik  *
1231c6fd2807SJeff Garzik  *      This routine simply redirects to the general purpose routine
1232c6fd2807SJeff Garzik  *      if command is not DMA.  Else, it sanity checks our local
1233c6fd2807SJeff Garzik  *      caches of the request producer/consumer indices then enables
1234c6fd2807SJeff Garzik  *      DMA and bumps the request producer index.
1235c6fd2807SJeff Garzik  *
1236c6fd2807SJeff Garzik  *      LOCKING:
1237c6fd2807SJeff Garzik  *      Inherited from caller.
1238c6fd2807SJeff Garzik  */
1239c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
1240c6fd2807SJeff Garzik {
1241c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(qc->ap);
1242c6fd2807SJeff Garzik 	struct mv_port_priv *pp = qc->ap->private_data;
1243c6fd2807SJeff Garzik 	unsigned in_index;
1244c6fd2807SJeff Garzik 	u32 in_ptr;
1245c6fd2807SJeff Garzik 
1246c6fd2807SJeff Garzik 	if (ATA_PROT_DMA != qc->tf.protocol) {
1247c6fd2807SJeff Garzik 		/* We're about to send a non-EDMA capable command to the
1248c6fd2807SJeff Garzik 		 * port.  Turn off EDMA so there won't be problems accessing
1249c6fd2807SJeff Garzik 		 * shadow block, etc registers.
1250c6fd2807SJeff Garzik 		 */
1251c6fd2807SJeff Garzik 		mv_stop_dma(qc->ap);
1252c6fd2807SJeff Garzik 		return ata_qc_issue_prot(qc);
1253c6fd2807SJeff Garzik 	}
1254c6fd2807SJeff Garzik 
1255c6fd2807SJeff Garzik 	in_ptr   = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
1256c6fd2807SJeff Garzik 	in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1257c6fd2807SJeff Garzik 
1258c6fd2807SJeff Garzik 	/* until we do queuing, the queue should be empty at this point */
1259c6fd2807SJeff Garzik 	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1260c6fd2807SJeff Garzik 		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
1261c6fd2807SJeff Garzik 
1262c6fd2807SJeff Garzik 	in_index = mv_inc_q_index(in_index);	/* now incr producer index */
1263c6fd2807SJeff Garzik 
1264c6fd2807SJeff Garzik 	mv_start_dma(port_mmio, pp);
1265c6fd2807SJeff Garzik 
1266c6fd2807SJeff Garzik 	/* and write the request in pointer to kick the EDMA to life */
1267c6fd2807SJeff Garzik 	in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
1268c6fd2807SJeff Garzik 	in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
1269c6fd2807SJeff Garzik 	writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
1270c6fd2807SJeff Garzik 
1271c6fd2807SJeff Garzik 	return 0;
1272c6fd2807SJeff Garzik }
1273c6fd2807SJeff Garzik 
1274c6fd2807SJeff Garzik /**
1275c6fd2807SJeff Garzik  *      mv_get_crpb_status - get status from most recently completed cmd
1276c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1277c6fd2807SJeff Garzik  *
1278c6fd2807SJeff Garzik  *      This routine is for use when the port is in DMA mode, when it
1279c6fd2807SJeff Garzik  *      will be using the CRPB (command response block) method of
1280c6fd2807SJeff Garzik  *      returning command completion information.  We check indices
1281c6fd2807SJeff Garzik  *      are good, grab status, and bump the response consumer index to
1282c6fd2807SJeff Garzik  *      prove that we're up to date.
1283c6fd2807SJeff Garzik  *
1284c6fd2807SJeff Garzik  *      LOCKING:
1285c6fd2807SJeff Garzik  *      Inherited from caller.
1286c6fd2807SJeff Garzik  */
1287c6fd2807SJeff Garzik static u8 mv_get_crpb_status(struct ata_port *ap)
1288c6fd2807SJeff Garzik {
1289c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1290c6fd2807SJeff Garzik 	struct mv_port_priv *pp = ap->private_data;
1291c6fd2807SJeff Garzik 	unsigned out_index;
1292c6fd2807SJeff Garzik 	u32 out_ptr;
1293c6fd2807SJeff Garzik 	u8 ata_status;
1294c6fd2807SJeff Garzik 
1295c6fd2807SJeff Garzik 	out_ptr   = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
1296c6fd2807SJeff Garzik 	out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1297c6fd2807SJeff Garzik 
1298c6fd2807SJeff Garzik 	ata_status = le16_to_cpu(pp->crpb[out_index].flags)
1299c6fd2807SJeff Garzik 					>> CRPB_FLAG_STATUS_SHIFT;
1300c6fd2807SJeff Garzik 
1301c6fd2807SJeff Garzik 	/* increment our consumer index... */
1302c6fd2807SJeff Garzik 	out_index = mv_inc_q_index(out_index);
1303c6fd2807SJeff Garzik 
1304c6fd2807SJeff Garzik 	/* and, until we do NCQ, there should only be 1 CRPB waiting */
1305c6fd2807SJeff Garzik 	WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1306c6fd2807SJeff Garzik 		>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
1307c6fd2807SJeff Garzik 
1308c6fd2807SJeff Garzik 	/* write out our inc'd consumer index so EDMA knows we're caught up */
1309c6fd2807SJeff Garzik 	out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
1310c6fd2807SJeff Garzik 	out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
1311c6fd2807SJeff Garzik 	writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
1312c6fd2807SJeff Garzik 
1313c6fd2807SJeff Garzik 	/* Return ATA status register for completed CRPB */
1314c6fd2807SJeff Garzik 	return ata_status;
1315c6fd2807SJeff Garzik }
1316c6fd2807SJeff Garzik 
1317c6fd2807SJeff Garzik /**
1318c6fd2807SJeff Garzik  *      mv_err_intr - Handle error interrupts on the port
1319c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1320c6fd2807SJeff Garzik  *      @reset_allowed: bool: 0 == don't trigger from reset here
1321c6fd2807SJeff Garzik  *
1322c6fd2807SJeff Garzik  *      In most cases, just clear the interrupt and move on.  However,
1323c6fd2807SJeff Garzik  *      some cases require an eDMA reset, which is done right before
1324c6fd2807SJeff Garzik  *      the COMRESET in mv_phy_reset().  The SERR case requires a
1325c6fd2807SJeff Garzik  *      clear of pending errors in the SATA SERROR register.  Finally,
1326c6fd2807SJeff Garzik  *      if the port disabled DMA, update our cached copy to match.
1327c6fd2807SJeff Garzik  *
1328c6fd2807SJeff Garzik  *      LOCKING:
1329c6fd2807SJeff Garzik  *      Inherited from caller.
1330c6fd2807SJeff Garzik  */
1331c6fd2807SJeff Garzik static void mv_err_intr(struct ata_port *ap, int reset_allowed)
1332c6fd2807SJeff Garzik {
1333c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1334c6fd2807SJeff Garzik 	u32 edma_err_cause, serr = 0;
1335c6fd2807SJeff Garzik 
1336c6fd2807SJeff Garzik 	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1337c6fd2807SJeff Garzik 
1338c6fd2807SJeff Garzik 	if (EDMA_ERR_SERR & edma_err_cause) {
1339c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_ERROR, &serr);
1340c6fd2807SJeff Garzik 		sata_scr_write_flush(ap, SCR_ERROR, serr);
1341c6fd2807SJeff Garzik 	}
1342c6fd2807SJeff Garzik 	if (EDMA_ERR_SELF_DIS & edma_err_cause) {
1343c6fd2807SJeff Garzik 		struct mv_port_priv *pp	= ap->private_data;
1344c6fd2807SJeff Garzik 		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1345c6fd2807SJeff Garzik 	}
1346c6fd2807SJeff Garzik 	DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
134744877b4eSTejun Heo 		"SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr);
1348c6fd2807SJeff Garzik 
1349c6fd2807SJeff Garzik 	/* Clear EDMA now that SERR cleanup done */
1350c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1351c6fd2807SJeff Garzik 
1352c6fd2807SJeff Garzik 	/* check for fatal here and recover if needed */
1353c6fd2807SJeff Garzik 	if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
1354c6fd2807SJeff Garzik 		mv_stop_and_reset(ap);
1355c6fd2807SJeff Garzik }
1356c6fd2807SJeff Garzik 
1357c6fd2807SJeff Garzik /**
1358c6fd2807SJeff Garzik  *      mv_host_intr - Handle all interrupts on the given host controller
1359cca3974eSJeff Garzik  *      @host: host specific structure
1360c6fd2807SJeff Garzik  *      @relevant: port error bits relevant to this host controller
1361c6fd2807SJeff Garzik  *      @hc: which host controller we're to look at
1362c6fd2807SJeff Garzik  *
1363c6fd2807SJeff Garzik  *      Read then write clear the HC interrupt status then walk each
1364c6fd2807SJeff Garzik  *      port connected to the HC and see if it needs servicing.  Port
1365c6fd2807SJeff Garzik  *      success ints are reported in the HC interrupt status reg, the
1366c6fd2807SJeff Garzik  *      port error ints are reported in the higher level main
1367c6fd2807SJeff Garzik  *      interrupt status register and thus are passed in via the
1368c6fd2807SJeff Garzik  *      'relevant' argument.
1369c6fd2807SJeff Garzik  *
1370c6fd2807SJeff Garzik  *      LOCKING:
1371c6fd2807SJeff Garzik  *      Inherited from caller.
1372c6fd2807SJeff Garzik  */
1373cca3974eSJeff Garzik static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
1374c6fd2807SJeff Garzik {
13750d5ff566STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
1376c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1377c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
1378c6fd2807SJeff Garzik 	u32 hc_irq_cause;
1379c6fd2807SJeff Garzik 	int shift, port, port0, hard_port, handled;
1380c6fd2807SJeff Garzik 	unsigned int err_mask;
1381c6fd2807SJeff Garzik 
138235177265SJeff Garzik 	if (hc == 0)
1383c6fd2807SJeff Garzik 		port0 = 0;
138435177265SJeff Garzik 	else
1385c6fd2807SJeff Garzik 		port0 = MV_PORTS_PER_HC;
1386c6fd2807SJeff Garzik 
1387c6fd2807SJeff Garzik 	/* we'll need the HC success int register in most cases */
1388c6fd2807SJeff Garzik 	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
138935177265SJeff Garzik 	if (hc_irq_cause)
1390c6fd2807SJeff Garzik 		writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
1391c6fd2807SJeff Garzik 
1392c6fd2807SJeff Garzik 	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
1393c6fd2807SJeff Garzik 		hc,relevant,hc_irq_cause);
1394c6fd2807SJeff Garzik 
1395c6fd2807SJeff Garzik 	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
1396c6fd2807SJeff Garzik 		u8 ata_status = 0;
1397cca3974eSJeff Garzik 		struct ata_port *ap = host->ports[port];
1398c6fd2807SJeff Garzik 		struct mv_port_priv *pp = ap->private_data;
1399c6fd2807SJeff Garzik 
1400c6fd2807SJeff Garzik 		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1401c6fd2807SJeff Garzik 		handled = 0;	/* ensure ata_status is set if handled++ */
1402c6fd2807SJeff Garzik 
1403c6fd2807SJeff Garzik 		/* Note that DEV_IRQ might happen spuriously during EDMA,
1404c6fd2807SJeff Garzik 		 * and should be ignored in such cases.
1405c6fd2807SJeff Garzik 		 * The cause of this is still under investigation.
1406c6fd2807SJeff Garzik 		 */
1407c6fd2807SJeff Garzik 		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1408c6fd2807SJeff Garzik 			/* EDMA: check for response queue interrupt */
1409c6fd2807SJeff Garzik 			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
1410c6fd2807SJeff Garzik 				ata_status = mv_get_crpb_status(ap);
1411c6fd2807SJeff Garzik 				handled = 1;
1412c6fd2807SJeff Garzik 			}
1413c6fd2807SJeff Garzik 		} else {
1414c6fd2807SJeff Garzik 			/* PIO: check for device (drive) interrupt */
1415c6fd2807SJeff Garzik 			if ((DEV_IRQ << hard_port) & hc_irq_cause) {
14160d5ff566STejun Heo 				ata_status = readb(ap->ioaddr.status_addr);
1417c6fd2807SJeff Garzik 				handled = 1;
1418c6fd2807SJeff Garzik 				/* ignore spurious intr if drive still BUSY */
1419c6fd2807SJeff Garzik 				if (ata_status & ATA_BUSY) {
1420c6fd2807SJeff Garzik 					ata_status = 0;
1421c6fd2807SJeff Garzik 					handled = 0;
1422c6fd2807SJeff Garzik 				}
1423c6fd2807SJeff Garzik 			}
1424c6fd2807SJeff Garzik 		}
1425c6fd2807SJeff Garzik 
1426c6fd2807SJeff Garzik 		if (ap && (ap->flags & ATA_FLAG_DISABLED))
1427c6fd2807SJeff Garzik 			continue;
1428c6fd2807SJeff Garzik 
1429c6fd2807SJeff Garzik 		err_mask = ac_err_mask(ata_status);
1430c6fd2807SJeff Garzik 
1431c6fd2807SJeff Garzik 		shift = port << 1;		/* (port * 2) */
1432c6fd2807SJeff Garzik 		if (port >= MV_PORTS_PER_HC) {
1433c6fd2807SJeff Garzik 			shift++;	/* skip bit 8 in the HC Main IRQ reg */
1434c6fd2807SJeff Garzik 		}
1435c6fd2807SJeff Garzik 		if ((PORT0_ERR << shift) & relevant) {
1436c6fd2807SJeff Garzik 			mv_err_intr(ap, 1);
1437c6fd2807SJeff Garzik 			err_mask |= AC_ERR_OTHER;
1438c6fd2807SJeff Garzik 			handled = 1;
1439c6fd2807SJeff Garzik 		}
1440c6fd2807SJeff Garzik 
1441c6fd2807SJeff Garzik 		if (handled) {
1442c6fd2807SJeff Garzik 			qc = ata_qc_from_tag(ap, ap->active_tag);
1443c6fd2807SJeff Garzik 			if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
1444c6fd2807SJeff Garzik 				VPRINTK("port %u IRQ found for qc, "
1445c6fd2807SJeff Garzik 					"ata_status 0x%x\n", port,ata_status);
1446c6fd2807SJeff Garzik 				/* mark qc status appropriately */
1447c6fd2807SJeff Garzik 				if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
1448c6fd2807SJeff Garzik 					qc->err_mask |= err_mask;
1449c6fd2807SJeff Garzik 					ata_qc_complete(qc);
1450c6fd2807SJeff Garzik 				}
1451c6fd2807SJeff Garzik 			}
1452c6fd2807SJeff Garzik 		}
1453c6fd2807SJeff Garzik 	}
1454c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1455c6fd2807SJeff Garzik }
1456c6fd2807SJeff Garzik 
1457c6fd2807SJeff Garzik /**
1458c6fd2807SJeff Garzik  *      mv_interrupt -
1459c6fd2807SJeff Garzik  *      @irq: unused
1460c6fd2807SJeff Garzik  *      @dev_instance: private data; in this case the host structure
1461c6fd2807SJeff Garzik  *      @regs: unused
1462c6fd2807SJeff Garzik  *
1463c6fd2807SJeff Garzik  *      Read the read only register to determine if any host
1464c6fd2807SJeff Garzik  *      controllers have pending interrupts.  If so, call lower level
1465c6fd2807SJeff Garzik  *      routine to handle.  Also check for PCI errors which are only
1466c6fd2807SJeff Garzik  *      reported here.
1467c6fd2807SJeff Garzik  *
1468c6fd2807SJeff Garzik  *      LOCKING:
1469cca3974eSJeff Garzik  *      This routine holds the host lock while processing pending
1470c6fd2807SJeff Garzik  *      interrupts.
1471c6fd2807SJeff Garzik  */
14727d12e780SDavid Howells static irqreturn_t mv_interrupt(int irq, void *dev_instance)
1473c6fd2807SJeff Garzik {
1474cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1475c6fd2807SJeff Garzik 	unsigned int hc, handled = 0, n_hcs;
14760d5ff566STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
1477c6fd2807SJeff Garzik 	struct mv_host_priv *hpriv;
1478c6fd2807SJeff Garzik 	u32 irq_stat;
1479c6fd2807SJeff Garzik 
1480c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
1481c6fd2807SJeff Garzik 
1482c6fd2807SJeff Garzik 	/* check the cases where we either have nothing pending or have read
1483c6fd2807SJeff Garzik 	 * a bogus register value which can indicate HW removal or PCI fault
1484c6fd2807SJeff Garzik 	 */
148535177265SJeff Garzik 	if (!irq_stat || (0xffffffffU == irq_stat))
1486c6fd2807SJeff Garzik 		return IRQ_NONE;
1487c6fd2807SJeff Garzik 
1488cca3974eSJeff Garzik 	n_hcs = mv_get_hc_count(host->ports[0]->flags);
1489cca3974eSJeff Garzik 	spin_lock(&host->lock);
1490c6fd2807SJeff Garzik 
1491c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hcs; hc++) {
1492c6fd2807SJeff Garzik 		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
1493c6fd2807SJeff Garzik 		if (relevant) {
1494cca3974eSJeff Garzik 			mv_host_intr(host, relevant, hc);
1495c6fd2807SJeff Garzik 			handled++;
1496c6fd2807SJeff Garzik 		}
1497c6fd2807SJeff Garzik 	}
1498c6fd2807SJeff Garzik 
1499cca3974eSJeff Garzik 	hpriv = host->private_data;
1500c6fd2807SJeff Garzik 	if (IS_60XX(hpriv)) {
1501c6fd2807SJeff Garzik 		/* deal with the interrupt coalescing bits */
1502c6fd2807SJeff Garzik 		if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
1503c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
1504c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
1505c6fd2807SJeff Garzik 			writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
1506c6fd2807SJeff Garzik 		}
1507c6fd2807SJeff Garzik 	}
1508c6fd2807SJeff Garzik 
1509c6fd2807SJeff Garzik 	if (PCI_ERR & irq_stat) {
1510c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
1511c6fd2807SJeff Garzik 		       readl(mmio + PCI_IRQ_CAUSE_OFS));
1512c6fd2807SJeff Garzik 
1513c6fd2807SJeff Garzik 		DPRINTK("All regs @ PCI error\n");
1514cca3974eSJeff Garzik 		mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1515c6fd2807SJeff Garzik 
1516c6fd2807SJeff Garzik 		writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
1517c6fd2807SJeff Garzik 		handled++;
1518c6fd2807SJeff Garzik 	}
1519cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1520c6fd2807SJeff Garzik 
1521c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1522c6fd2807SJeff Garzik }
1523c6fd2807SJeff Garzik 
1524c6fd2807SJeff Garzik static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1525c6fd2807SJeff Garzik {
1526c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1527c6fd2807SJeff Garzik 	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1528c6fd2807SJeff Garzik 
1529c6fd2807SJeff Garzik 	return hc_mmio + ofs;
1530c6fd2807SJeff Garzik }
1531c6fd2807SJeff Garzik 
1532c6fd2807SJeff Garzik static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1533c6fd2807SJeff Garzik {
1534c6fd2807SJeff Garzik 	unsigned int ofs;
1535c6fd2807SJeff Garzik 
1536c6fd2807SJeff Garzik 	switch (sc_reg_in) {
1537c6fd2807SJeff Garzik 	case SCR_STATUS:
1538c6fd2807SJeff Garzik 	case SCR_ERROR:
1539c6fd2807SJeff Garzik 	case SCR_CONTROL:
1540c6fd2807SJeff Garzik 		ofs = sc_reg_in * sizeof(u32);
1541c6fd2807SJeff Garzik 		break;
1542c6fd2807SJeff Garzik 	default:
1543c6fd2807SJeff Garzik 		ofs = 0xffffffffU;
1544c6fd2807SJeff Garzik 		break;
1545c6fd2807SJeff Garzik 	}
1546c6fd2807SJeff Garzik 	return ofs;
1547c6fd2807SJeff Garzik }
1548c6fd2807SJeff Garzik 
1549c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
1550c6fd2807SJeff Garzik {
15510d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
15520d5ff566STejun Heo 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1553c6fd2807SJeff Garzik 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1554c6fd2807SJeff Garzik 
1555c6fd2807SJeff Garzik 	if (ofs != 0xffffffffU)
15560d5ff566STejun Heo 		return readl(addr + ofs);
1557c6fd2807SJeff Garzik 	else
1558c6fd2807SJeff Garzik 		return (u32) ofs;
1559c6fd2807SJeff Garzik }
1560c6fd2807SJeff Garzik 
1561c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1562c6fd2807SJeff Garzik {
15630d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
15640d5ff566STejun Heo 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1565c6fd2807SJeff Garzik 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1566c6fd2807SJeff Garzik 
1567c6fd2807SJeff Garzik 	if (ofs != 0xffffffffU)
15680d5ff566STejun Heo 		writelfl(val, addr + ofs);
1569c6fd2807SJeff Garzik }
1570c6fd2807SJeff Garzik 
1571c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1572c6fd2807SJeff Garzik {
1573c6fd2807SJeff Garzik 	u8 rev_id;
1574c6fd2807SJeff Garzik 	int early_5080;
1575c6fd2807SJeff Garzik 
1576c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
1577c6fd2807SJeff Garzik 
1578c6fd2807SJeff Garzik 	early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
1579c6fd2807SJeff Garzik 
1580c6fd2807SJeff Garzik 	if (!early_5080) {
1581c6fd2807SJeff Garzik 		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1582c6fd2807SJeff Garzik 		tmp |= (1 << 0);
1583c6fd2807SJeff Garzik 		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1584c6fd2807SJeff Garzik 	}
1585c6fd2807SJeff Garzik 
1586c6fd2807SJeff Garzik 	mv_reset_pci_bus(pdev, mmio);
1587c6fd2807SJeff Garzik }
1588c6fd2807SJeff Garzik 
1589c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1590c6fd2807SJeff Garzik {
1591c6fd2807SJeff Garzik 	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1592c6fd2807SJeff Garzik }
1593c6fd2807SJeff Garzik 
1594c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1595c6fd2807SJeff Garzik 			   void __iomem *mmio)
1596c6fd2807SJeff Garzik {
1597c6fd2807SJeff Garzik 	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1598c6fd2807SJeff Garzik 	u32 tmp;
1599c6fd2807SJeff Garzik 
1600c6fd2807SJeff Garzik 	tmp = readl(phy_mmio + MV5_PHY_MODE);
1601c6fd2807SJeff Garzik 
1602c6fd2807SJeff Garzik 	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1603c6fd2807SJeff Garzik 	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1604c6fd2807SJeff Garzik }
1605c6fd2807SJeff Garzik 
1606c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1607c6fd2807SJeff Garzik {
1608c6fd2807SJeff Garzik 	u32 tmp;
1609c6fd2807SJeff Garzik 
1610c6fd2807SJeff Garzik 	writel(0, mmio + MV_GPIO_PORT_CTL);
1611c6fd2807SJeff Garzik 
1612c6fd2807SJeff Garzik 	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1613c6fd2807SJeff Garzik 
1614c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1615c6fd2807SJeff Garzik 	tmp |= ~(1 << 0);
1616c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1617c6fd2807SJeff Garzik }
1618c6fd2807SJeff Garzik 
1619c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
1620c6fd2807SJeff Garzik 			   unsigned int port)
1621c6fd2807SJeff Garzik {
1622c6fd2807SJeff Garzik 	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1623c6fd2807SJeff Garzik 	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1624c6fd2807SJeff Garzik 	u32 tmp;
1625c6fd2807SJeff Garzik 	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1626c6fd2807SJeff Garzik 
1627c6fd2807SJeff Garzik 	if (fix_apm_sq) {
1628c6fd2807SJeff Garzik 		tmp = readl(phy_mmio + MV5_LT_MODE);
1629c6fd2807SJeff Garzik 		tmp |= (1 << 19);
1630c6fd2807SJeff Garzik 		writel(tmp, phy_mmio + MV5_LT_MODE);
1631c6fd2807SJeff Garzik 
1632c6fd2807SJeff Garzik 		tmp = readl(phy_mmio + MV5_PHY_CTL);
1633c6fd2807SJeff Garzik 		tmp &= ~0x3;
1634c6fd2807SJeff Garzik 		tmp |= 0x1;
1635c6fd2807SJeff Garzik 		writel(tmp, phy_mmio + MV5_PHY_CTL);
1636c6fd2807SJeff Garzik 	}
1637c6fd2807SJeff Garzik 
1638c6fd2807SJeff Garzik 	tmp = readl(phy_mmio + MV5_PHY_MODE);
1639c6fd2807SJeff Garzik 	tmp &= ~mask;
1640c6fd2807SJeff Garzik 	tmp |= hpriv->signal[port].pre;
1641c6fd2807SJeff Garzik 	tmp |= hpriv->signal[port].amps;
1642c6fd2807SJeff Garzik 	writel(tmp, phy_mmio + MV5_PHY_MODE);
1643c6fd2807SJeff Garzik }
1644c6fd2807SJeff Garzik 
1645c6fd2807SJeff Garzik 
1646c6fd2807SJeff Garzik #undef ZERO
1647c6fd2807SJeff Garzik #define ZERO(reg) writel(0, port_mmio + (reg))
1648c6fd2807SJeff Garzik static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1649c6fd2807SJeff Garzik 			     unsigned int port)
1650c6fd2807SJeff Garzik {
1651c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port);
1652c6fd2807SJeff Garzik 
1653c6fd2807SJeff Garzik 	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1654c6fd2807SJeff Garzik 
1655c6fd2807SJeff Garzik 	mv_channel_reset(hpriv, mmio, port);
1656c6fd2807SJeff Garzik 
1657c6fd2807SJeff Garzik 	ZERO(0x028);	/* command */
1658c6fd2807SJeff Garzik 	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1659c6fd2807SJeff Garzik 	ZERO(0x004);	/* timer */
1660c6fd2807SJeff Garzik 	ZERO(0x008);	/* irq err cause */
1661c6fd2807SJeff Garzik 	ZERO(0x00c);	/* irq err mask */
1662c6fd2807SJeff Garzik 	ZERO(0x010);	/* rq bah */
1663c6fd2807SJeff Garzik 	ZERO(0x014);	/* rq inp */
1664c6fd2807SJeff Garzik 	ZERO(0x018);	/* rq outp */
1665c6fd2807SJeff Garzik 	ZERO(0x01c);	/* respq bah */
1666c6fd2807SJeff Garzik 	ZERO(0x024);	/* respq outp */
1667c6fd2807SJeff Garzik 	ZERO(0x020);	/* respq inp */
1668c6fd2807SJeff Garzik 	ZERO(0x02c);	/* test control */
1669c6fd2807SJeff Garzik 	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1670c6fd2807SJeff Garzik }
1671c6fd2807SJeff Garzik #undef ZERO
1672c6fd2807SJeff Garzik 
1673c6fd2807SJeff Garzik #define ZERO(reg) writel(0, hc_mmio + (reg))
1674c6fd2807SJeff Garzik static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1675c6fd2807SJeff Garzik 			unsigned int hc)
1676c6fd2807SJeff Garzik {
1677c6fd2807SJeff Garzik 	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1678c6fd2807SJeff Garzik 	u32 tmp;
1679c6fd2807SJeff Garzik 
1680c6fd2807SJeff Garzik 	ZERO(0x00c);
1681c6fd2807SJeff Garzik 	ZERO(0x010);
1682c6fd2807SJeff Garzik 	ZERO(0x014);
1683c6fd2807SJeff Garzik 	ZERO(0x018);
1684c6fd2807SJeff Garzik 
1685c6fd2807SJeff Garzik 	tmp = readl(hc_mmio + 0x20);
1686c6fd2807SJeff Garzik 	tmp &= 0x1c1c1c1c;
1687c6fd2807SJeff Garzik 	tmp |= 0x03030303;
1688c6fd2807SJeff Garzik 	writel(tmp, hc_mmio + 0x20);
1689c6fd2807SJeff Garzik }
1690c6fd2807SJeff Garzik #undef ZERO
1691c6fd2807SJeff Garzik 
1692c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1693c6fd2807SJeff Garzik 			unsigned int n_hc)
1694c6fd2807SJeff Garzik {
1695c6fd2807SJeff Garzik 	unsigned int hc, port;
1696c6fd2807SJeff Garzik 
1697c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hc; hc++) {
1698c6fd2807SJeff Garzik 		for (port = 0; port < MV_PORTS_PER_HC; port++)
1699c6fd2807SJeff Garzik 			mv5_reset_hc_port(hpriv, mmio,
1700c6fd2807SJeff Garzik 					  (hc * MV_PORTS_PER_HC) + port);
1701c6fd2807SJeff Garzik 
1702c6fd2807SJeff Garzik 		mv5_reset_one_hc(hpriv, mmio, hc);
1703c6fd2807SJeff Garzik 	}
1704c6fd2807SJeff Garzik 
1705c6fd2807SJeff Garzik 	return 0;
1706c6fd2807SJeff Garzik }
1707c6fd2807SJeff Garzik 
1708c6fd2807SJeff Garzik #undef ZERO
1709c6fd2807SJeff Garzik #define ZERO(reg) writel(0, mmio + (reg))
1710c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1711c6fd2807SJeff Garzik {
1712c6fd2807SJeff Garzik 	u32 tmp;
1713c6fd2807SJeff Garzik 
1714c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_PCI_MODE);
1715c6fd2807SJeff Garzik 	tmp &= 0xff00ffff;
1716c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_PCI_MODE);
1717c6fd2807SJeff Garzik 
1718c6fd2807SJeff Garzik 	ZERO(MV_PCI_DISC_TIMER);
1719c6fd2807SJeff Garzik 	ZERO(MV_PCI_MSI_TRIGGER);
1720c6fd2807SJeff Garzik 	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1721c6fd2807SJeff Garzik 	ZERO(HC_MAIN_IRQ_MASK_OFS);
1722c6fd2807SJeff Garzik 	ZERO(MV_PCI_SERR_MASK);
1723c6fd2807SJeff Garzik 	ZERO(PCI_IRQ_CAUSE_OFS);
1724c6fd2807SJeff Garzik 	ZERO(PCI_IRQ_MASK_OFS);
1725c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_LOW_ADDRESS);
1726c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1727c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_ATTRIBUTE);
1728c6fd2807SJeff Garzik 	ZERO(MV_PCI_ERR_COMMAND);
1729c6fd2807SJeff Garzik }
1730c6fd2807SJeff Garzik #undef ZERO
1731c6fd2807SJeff Garzik 
1732c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1733c6fd2807SJeff Garzik {
1734c6fd2807SJeff Garzik 	u32 tmp;
1735c6fd2807SJeff Garzik 
1736c6fd2807SJeff Garzik 	mv5_reset_flash(hpriv, mmio);
1737c6fd2807SJeff Garzik 
1738c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_GPIO_PORT_CTL);
1739c6fd2807SJeff Garzik 	tmp &= 0x3;
1740c6fd2807SJeff Garzik 	tmp |= (1 << 5) | (1 << 6);
1741c6fd2807SJeff Garzik 	writel(tmp, mmio + MV_GPIO_PORT_CTL);
1742c6fd2807SJeff Garzik }
1743c6fd2807SJeff Garzik 
1744c6fd2807SJeff Garzik /**
1745c6fd2807SJeff Garzik  *      mv6_reset_hc - Perform the 6xxx global soft reset
1746c6fd2807SJeff Garzik  *      @mmio: base address of the HBA
1747c6fd2807SJeff Garzik  *
1748c6fd2807SJeff Garzik  *      This routine only applies to 6xxx parts.
1749c6fd2807SJeff Garzik  *
1750c6fd2807SJeff Garzik  *      LOCKING:
1751c6fd2807SJeff Garzik  *      Inherited from caller.
1752c6fd2807SJeff Garzik  */
1753c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1754c6fd2807SJeff Garzik 			unsigned int n_hc)
1755c6fd2807SJeff Garzik {
1756c6fd2807SJeff Garzik 	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1757c6fd2807SJeff Garzik 	int i, rc = 0;
1758c6fd2807SJeff Garzik 	u32 t;
1759c6fd2807SJeff Garzik 
1760c6fd2807SJeff Garzik 	/* Following procedure defined in PCI "main command and status
1761c6fd2807SJeff Garzik 	 * register" table.
1762c6fd2807SJeff Garzik 	 */
1763c6fd2807SJeff Garzik 	t = readl(reg);
1764c6fd2807SJeff Garzik 	writel(t | STOP_PCI_MASTER, reg);
1765c6fd2807SJeff Garzik 
1766c6fd2807SJeff Garzik 	for (i = 0; i < 1000; i++) {
1767c6fd2807SJeff Garzik 		udelay(1);
1768c6fd2807SJeff Garzik 		t = readl(reg);
1769c6fd2807SJeff Garzik 		if (PCI_MASTER_EMPTY & t) {
1770c6fd2807SJeff Garzik 			break;
1771c6fd2807SJeff Garzik 		}
1772c6fd2807SJeff Garzik 	}
1773c6fd2807SJeff Garzik 	if (!(PCI_MASTER_EMPTY & t)) {
1774c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
1775c6fd2807SJeff Garzik 		rc = 1;
1776c6fd2807SJeff Garzik 		goto done;
1777c6fd2807SJeff Garzik 	}
1778c6fd2807SJeff Garzik 
1779c6fd2807SJeff Garzik 	/* set reset */
1780c6fd2807SJeff Garzik 	i = 5;
1781c6fd2807SJeff Garzik 	do {
1782c6fd2807SJeff Garzik 		writel(t | GLOB_SFT_RST, reg);
1783c6fd2807SJeff Garzik 		t = readl(reg);
1784c6fd2807SJeff Garzik 		udelay(1);
1785c6fd2807SJeff Garzik 	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
1786c6fd2807SJeff Garzik 
1787c6fd2807SJeff Garzik 	if (!(GLOB_SFT_RST & t)) {
1788c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
1789c6fd2807SJeff Garzik 		rc = 1;
1790c6fd2807SJeff Garzik 		goto done;
1791c6fd2807SJeff Garzik 	}
1792c6fd2807SJeff Garzik 
1793c6fd2807SJeff Garzik 	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
1794c6fd2807SJeff Garzik 	i = 5;
1795c6fd2807SJeff Garzik 	do {
1796c6fd2807SJeff Garzik 		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
1797c6fd2807SJeff Garzik 		t = readl(reg);
1798c6fd2807SJeff Garzik 		udelay(1);
1799c6fd2807SJeff Garzik 	} while ((GLOB_SFT_RST & t) && (i-- > 0));
1800c6fd2807SJeff Garzik 
1801c6fd2807SJeff Garzik 	if (GLOB_SFT_RST & t) {
1802c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
1803c6fd2807SJeff Garzik 		rc = 1;
1804c6fd2807SJeff Garzik 	}
1805c6fd2807SJeff Garzik done:
1806c6fd2807SJeff Garzik 	return rc;
1807c6fd2807SJeff Garzik }
1808c6fd2807SJeff Garzik 
1809c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
1810c6fd2807SJeff Garzik 			   void __iomem *mmio)
1811c6fd2807SJeff Garzik {
1812c6fd2807SJeff Garzik 	void __iomem *port_mmio;
1813c6fd2807SJeff Garzik 	u32 tmp;
1814c6fd2807SJeff Garzik 
1815c6fd2807SJeff Garzik 	tmp = readl(mmio + MV_RESET_CFG);
1816c6fd2807SJeff Garzik 	if ((tmp & (1 << 0)) == 0) {
1817c6fd2807SJeff Garzik 		hpriv->signal[idx].amps = 0x7 << 8;
1818c6fd2807SJeff Garzik 		hpriv->signal[idx].pre = 0x1 << 5;
1819c6fd2807SJeff Garzik 		return;
1820c6fd2807SJeff Garzik 	}
1821c6fd2807SJeff Garzik 
1822c6fd2807SJeff Garzik 	port_mmio = mv_port_base(mmio, idx);
1823c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PHY_MODE2);
1824c6fd2807SJeff Garzik 
1825c6fd2807SJeff Garzik 	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
1826c6fd2807SJeff Garzik 	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
1827c6fd2807SJeff Garzik }
1828c6fd2807SJeff Garzik 
1829c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1830c6fd2807SJeff Garzik {
1831c6fd2807SJeff Garzik 	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
1832c6fd2807SJeff Garzik }
1833c6fd2807SJeff Garzik 
1834c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
1835c6fd2807SJeff Garzik 			   unsigned int port)
1836c6fd2807SJeff Garzik {
1837c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port);
1838c6fd2807SJeff Garzik 
1839c6fd2807SJeff Garzik 	u32 hp_flags = hpriv->hp_flags;
1840c6fd2807SJeff Garzik 	int fix_phy_mode2 =
1841c6fd2807SJeff Garzik 		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
1842c6fd2807SJeff Garzik 	int fix_phy_mode4 =
1843c6fd2807SJeff Garzik 		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
1844c6fd2807SJeff Garzik 	u32 m2, tmp;
1845c6fd2807SJeff Garzik 
1846c6fd2807SJeff Garzik 	if (fix_phy_mode2) {
1847c6fd2807SJeff Garzik 		m2 = readl(port_mmio + PHY_MODE2);
1848c6fd2807SJeff Garzik 		m2 &= ~(1 << 16);
1849c6fd2807SJeff Garzik 		m2 |= (1 << 31);
1850c6fd2807SJeff Garzik 		writel(m2, port_mmio + PHY_MODE2);
1851c6fd2807SJeff Garzik 
1852c6fd2807SJeff Garzik 		udelay(200);
1853c6fd2807SJeff Garzik 
1854c6fd2807SJeff Garzik 		m2 = readl(port_mmio + PHY_MODE2);
1855c6fd2807SJeff Garzik 		m2 &= ~((1 << 16) | (1 << 31));
1856c6fd2807SJeff Garzik 		writel(m2, port_mmio + PHY_MODE2);
1857c6fd2807SJeff Garzik 
1858c6fd2807SJeff Garzik 		udelay(200);
1859c6fd2807SJeff Garzik 	}
1860c6fd2807SJeff Garzik 
1861c6fd2807SJeff Garzik 	/* who knows what this magic does */
1862c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PHY_MODE3);
1863c6fd2807SJeff Garzik 	tmp &= ~0x7F800000;
1864c6fd2807SJeff Garzik 	tmp |= 0x2A800000;
1865c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PHY_MODE3);
1866c6fd2807SJeff Garzik 
1867c6fd2807SJeff Garzik 	if (fix_phy_mode4) {
1868c6fd2807SJeff Garzik 		u32 m4;
1869c6fd2807SJeff Garzik 
1870c6fd2807SJeff Garzik 		m4 = readl(port_mmio + PHY_MODE4);
1871c6fd2807SJeff Garzik 
1872c6fd2807SJeff Garzik 		if (hp_flags & MV_HP_ERRATA_60X1B2)
1873c6fd2807SJeff Garzik 			tmp = readl(port_mmio + 0x310);
1874c6fd2807SJeff Garzik 
1875c6fd2807SJeff Garzik 		m4 = (m4 & ~(1 << 1)) | (1 << 0);
1876c6fd2807SJeff Garzik 
1877c6fd2807SJeff Garzik 		writel(m4, port_mmio + PHY_MODE4);
1878c6fd2807SJeff Garzik 
1879c6fd2807SJeff Garzik 		if (hp_flags & MV_HP_ERRATA_60X1B2)
1880c6fd2807SJeff Garzik 			writel(tmp, port_mmio + 0x310);
1881c6fd2807SJeff Garzik 	}
1882c6fd2807SJeff Garzik 
1883c6fd2807SJeff Garzik 	/* Revert values of pre-emphasis and signal amps to the saved ones */
1884c6fd2807SJeff Garzik 	m2 = readl(port_mmio + PHY_MODE2);
1885c6fd2807SJeff Garzik 
1886c6fd2807SJeff Garzik 	m2 &= ~MV_M2_PREAMP_MASK;
1887c6fd2807SJeff Garzik 	m2 |= hpriv->signal[port].amps;
1888c6fd2807SJeff Garzik 	m2 |= hpriv->signal[port].pre;
1889c6fd2807SJeff Garzik 	m2 &= ~(1 << 16);
1890c6fd2807SJeff Garzik 
1891c6fd2807SJeff Garzik 	/* according to mvSata 3.6.1, some IIE values are fixed */
1892c6fd2807SJeff Garzik 	if (IS_GEN_IIE(hpriv)) {
1893c6fd2807SJeff Garzik 		m2 &= ~0xC30FF01F;
1894c6fd2807SJeff Garzik 		m2 |= 0x0000900F;
1895c6fd2807SJeff Garzik 	}
1896c6fd2807SJeff Garzik 
1897c6fd2807SJeff Garzik 	writel(m2, port_mmio + PHY_MODE2);
1898c6fd2807SJeff Garzik }
1899c6fd2807SJeff Garzik 
1900c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
1901c6fd2807SJeff Garzik 			     unsigned int port_no)
1902c6fd2807SJeff Garzik {
1903c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_port_base(mmio, port_no);
1904c6fd2807SJeff Garzik 
1905c6fd2807SJeff Garzik 	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
1906c6fd2807SJeff Garzik 
1907c6fd2807SJeff Garzik 	if (IS_60XX(hpriv)) {
1908c6fd2807SJeff Garzik 		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
1909c6fd2807SJeff Garzik 		ifctl |= (1 << 7);		/* enable gen2i speed */
1910c6fd2807SJeff Garzik 		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
1911c6fd2807SJeff Garzik 		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
1912c6fd2807SJeff Garzik 	}
1913c6fd2807SJeff Garzik 
1914c6fd2807SJeff Garzik 	udelay(25);		/* allow reset propagation */
1915c6fd2807SJeff Garzik 
1916c6fd2807SJeff Garzik 	/* Spec never mentions clearing the bit.  Marvell's driver does
1917c6fd2807SJeff Garzik 	 * clear the bit, however.
1918c6fd2807SJeff Garzik 	 */
1919c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_CMD_OFS);
1920c6fd2807SJeff Garzik 
1921c6fd2807SJeff Garzik 	hpriv->ops->phy_errata(hpriv, mmio, port_no);
1922c6fd2807SJeff Garzik 
1923c6fd2807SJeff Garzik 	if (IS_50XX(hpriv))
1924c6fd2807SJeff Garzik 		mdelay(1);
1925c6fd2807SJeff Garzik }
1926c6fd2807SJeff Garzik 
1927c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap)
1928c6fd2807SJeff Garzik {
1929cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
19300d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
1931c6fd2807SJeff Garzik 
1932c6fd2807SJeff Garzik 	mv_stop_dma(ap);
1933c6fd2807SJeff Garzik 
1934c6fd2807SJeff Garzik 	mv_channel_reset(hpriv, mmio, ap->port_no);
1935c6fd2807SJeff Garzik 
1936c6fd2807SJeff Garzik 	__mv_phy_reset(ap, 0);
1937c6fd2807SJeff Garzik }
1938c6fd2807SJeff Garzik 
1939c6fd2807SJeff Garzik static inline void __msleep(unsigned int msec, int can_sleep)
1940c6fd2807SJeff Garzik {
1941c6fd2807SJeff Garzik 	if (can_sleep)
1942c6fd2807SJeff Garzik 		msleep(msec);
1943c6fd2807SJeff Garzik 	else
1944c6fd2807SJeff Garzik 		mdelay(msec);
1945c6fd2807SJeff Garzik }
1946c6fd2807SJeff Garzik 
1947c6fd2807SJeff Garzik /**
1948c6fd2807SJeff Garzik  *      __mv_phy_reset - Perform eDMA reset followed by COMRESET
1949c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
1950c6fd2807SJeff Garzik  *
1951c6fd2807SJeff Garzik  *      Part of this is taken from __sata_phy_reset and modified to
1952c6fd2807SJeff Garzik  *      not sleep since this routine gets called from interrupt level.
1953c6fd2807SJeff Garzik  *
1954c6fd2807SJeff Garzik  *      LOCKING:
1955c6fd2807SJeff Garzik  *      Inherited from caller.  This is coded to safe to call at
1956c6fd2807SJeff Garzik  *      interrupt level, i.e. it does not sleep.
1957c6fd2807SJeff Garzik  */
1958c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
1959c6fd2807SJeff Garzik {
1960c6fd2807SJeff Garzik 	struct mv_port_priv *pp	= ap->private_data;
1961cca3974eSJeff Garzik 	struct mv_host_priv *hpriv = ap->host->private_data;
1962c6fd2807SJeff Garzik 	void __iomem *port_mmio = mv_ap_base(ap);
1963c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1964c6fd2807SJeff Garzik 	struct ata_device *dev = &ap->device[0];
1965c6fd2807SJeff Garzik 	unsigned long timeout;
1966c6fd2807SJeff Garzik 	int retry = 5;
1967c6fd2807SJeff Garzik 	u32 sstatus;
1968c6fd2807SJeff Garzik 
1969c6fd2807SJeff Garzik 	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
1970c6fd2807SJeff Garzik 
1971c6fd2807SJeff Garzik 	DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
1972c6fd2807SJeff Garzik 		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
1973c6fd2807SJeff Garzik 		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
1974c6fd2807SJeff Garzik 
1975c6fd2807SJeff Garzik 	/* Issue COMRESET via SControl */
1976c6fd2807SJeff Garzik comreset_retry:
1977c6fd2807SJeff Garzik 	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
1978c6fd2807SJeff Garzik 	__msleep(1, can_sleep);
1979c6fd2807SJeff Garzik 
1980c6fd2807SJeff Garzik 	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
1981c6fd2807SJeff Garzik 	__msleep(20, can_sleep);
1982c6fd2807SJeff Garzik 
1983c6fd2807SJeff Garzik 	timeout = jiffies + msecs_to_jiffies(200);
1984c6fd2807SJeff Garzik 	do {
1985c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_STATUS, &sstatus);
1986dd1dc802SJeff Garzik 		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
1987c6fd2807SJeff Garzik 			break;
1988c6fd2807SJeff Garzik 
1989c6fd2807SJeff Garzik 		__msleep(1, can_sleep);
1990c6fd2807SJeff Garzik 	} while (time_before(jiffies, timeout));
1991c6fd2807SJeff Garzik 
1992c6fd2807SJeff Garzik 	/* work around errata */
1993c6fd2807SJeff Garzik 	if (IS_60XX(hpriv) &&
1994c6fd2807SJeff Garzik 	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
1995c6fd2807SJeff Garzik 	    (retry-- > 0))
1996c6fd2807SJeff Garzik 		goto comreset_retry;
1997c6fd2807SJeff Garzik 
1998c6fd2807SJeff Garzik 	DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
1999c6fd2807SJeff Garzik 		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
2000c6fd2807SJeff Garzik 		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
2001c6fd2807SJeff Garzik 
2002c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
2003c6fd2807SJeff Garzik 		ata_port_probe(ap);
2004c6fd2807SJeff Garzik 	} else {
2005c6fd2807SJeff Garzik 		sata_scr_read(ap, SCR_STATUS, &sstatus);
2006c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO,
2007c6fd2807SJeff Garzik 				"no device found (phy stat %08x)\n", sstatus);
2008c6fd2807SJeff Garzik 		ata_port_disable(ap);
2009c6fd2807SJeff Garzik 		return;
2010c6fd2807SJeff Garzik 	}
2011c6fd2807SJeff Garzik 
2012c6fd2807SJeff Garzik 	/* even after SStatus reflects that device is ready,
2013c6fd2807SJeff Garzik 	 * it seems to take a while for link to be fully
2014c6fd2807SJeff Garzik 	 * established (and thus Status no longer 0x80/0x7F),
2015c6fd2807SJeff Garzik 	 * so we poll a bit for that, here.
2016c6fd2807SJeff Garzik 	 */
2017c6fd2807SJeff Garzik 	retry = 20;
2018c6fd2807SJeff Garzik 	while (1) {
2019c6fd2807SJeff Garzik 		u8 drv_stat = ata_check_status(ap);
2020c6fd2807SJeff Garzik 		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
2021c6fd2807SJeff Garzik 			break;
2022c6fd2807SJeff Garzik 		__msleep(500, can_sleep);
2023c6fd2807SJeff Garzik 		if (retry-- <= 0)
2024c6fd2807SJeff Garzik 			break;
2025c6fd2807SJeff Garzik 	}
2026c6fd2807SJeff Garzik 
20270d5ff566STejun Heo 	tf.lbah = readb(ap->ioaddr.lbah_addr);
20280d5ff566STejun Heo 	tf.lbam = readb(ap->ioaddr.lbam_addr);
20290d5ff566STejun Heo 	tf.lbal = readb(ap->ioaddr.lbal_addr);
20300d5ff566STejun Heo 	tf.nsect = readb(ap->ioaddr.nsect_addr);
2031c6fd2807SJeff Garzik 
2032c6fd2807SJeff Garzik 	dev->class = ata_dev_classify(&tf);
2033c6fd2807SJeff Garzik 	if (!ata_dev_enabled(dev)) {
2034c6fd2807SJeff Garzik 		VPRINTK("Port disabled post-sig: No device present.\n");
2035c6fd2807SJeff Garzik 		ata_port_disable(ap);
2036c6fd2807SJeff Garzik 	}
2037c6fd2807SJeff Garzik 
2038c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2039c6fd2807SJeff Garzik 
2040c6fd2807SJeff Garzik 	pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
2041c6fd2807SJeff Garzik 
2042c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2043c6fd2807SJeff Garzik }
2044c6fd2807SJeff Garzik 
2045c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap)
2046c6fd2807SJeff Garzik {
2047c6fd2807SJeff Garzik 	__mv_phy_reset(ap, 1);
2048c6fd2807SJeff Garzik }
2049c6fd2807SJeff Garzik 
2050c6fd2807SJeff Garzik /**
2051c6fd2807SJeff Garzik  *      mv_eng_timeout - Routine called by libata when SCSI times out I/O
2052c6fd2807SJeff Garzik  *      @ap: ATA channel to manipulate
2053c6fd2807SJeff Garzik  *
2054c6fd2807SJeff Garzik  *      Intent is to clear all pending error conditions, reset the
2055c6fd2807SJeff Garzik  *      chip/bus, fail the command, and move on.
2056c6fd2807SJeff Garzik  *
2057c6fd2807SJeff Garzik  *      LOCKING:
2058cca3974eSJeff Garzik  *      This routine holds the host lock while failing the command.
2059c6fd2807SJeff Garzik  */
2060c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap)
2061c6fd2807SJeff Garzik {
20620d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2063c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
2064c6fd2807SJeff Garzik 	unsigned long flags;
2065c6fd2807SJeff Garzik 
2066c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
2067c6fd2807SJeff Garzik 	DPRINTK("All regs @ start of eng_timeout\n");
20680d5ff566STejun Heo 	mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev));
2069c6fd2807SJeff Garzik 
2070c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
2071c6fd2807SJeff Garzik         printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
20720d5ff566STejun Heo 	       mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
2073c6fd2807SJeff Garzik 
2074cca3974eSJeff Garzik 	spin_lock_irqsave(&ap->host->lock, flags);
2075c6fd2807SJeff Garzik 	mv_err_intr(ap, 0);
2076c6fd2807SJeff Garzik 	mv_stop_and_reset(ap);
2077cca3974eSJeff Garzik 	spin_unlock_irqrestore(&ap->host->lock, flags);
2078c6fd2807SJeff Garzik 
2079c6fd2807SJeff Garzik 	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
2080c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_ACTIVE) {
2081c6fd2807SJeff Garzik 		qc->err_mask |= AC_ERR_TIMEOUT;
2082c6fd2807SJeff Garzik 		ata_eh_qc_complete(qc);
2083c6fd2807SJeff Garzik 	}
2084c6fd2807SJeff Garzik }
2085c6fd2807SJeff Garzik 
2086c6fd2807SJeff Garzik /**
2087c6fd2807SJeff Garzik  *      mv_port_init - Perform some early initialization on a single port.
2088c6fd2807SJeff Garzik  *      @port: libata data structure storing shadow register addresses
2089c6fd2807SJeff Garzik  *      @port_mmio: base address of the port
2090c6fd2807SJeff Garzik  *
2091c6fd2807SJeff Garzik  *      Initialize shadow register mmio addresses, clear outstanding
2092c6fd2807SJeff Garzik  *      interrupts on the port, and unmask interrupts for the future
2093c6fd2807SJeff Garzik  *      start of the port.
2094c6fd2807SJeff Garzik  *
2095c6fd2807SJeff Garzik  *      LOCKING:
2096c6fd2807SJeff Garzik  *      Inherited from caller.
2097c6fd2807SJeff Garzik  */
2098c6fd2807SJeff Garzik static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
2099c6fd2807SJeff Garzik {
21000d5ff566STejun Heo 	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
2101c6fd2807SJeff Garzik 	unsigned serr_ofs;
2102c6fd2807SJeff Garzik 
2103c6fd2807SJeff Garzik 	/* PIO related setup
2104c6fd2807SJeff Garzik 	 */
2105c6fd2807SJeff Garzik 	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
2106c6fd2807SJeff Garzik 	port->error_addr =
2107c6fd2807SJeff Garzik 		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
2108c6fd2807SJeff Garzik 	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
2109c6fd2807SJeff Garzik 	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
2110c6fd2807SJeff Garzik 	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
2111c6fd2807SJeff Garzik 	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
2112c6fd2807SJeff Garzik 	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
2113c6fd2807SJeff Garzik 	port->status_addr =
2114c6fd2807SJeff Garzik 		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
2115c6fd2807SJeff Garzik 	/* special case: control/altstatus doesn't have ATA_REG_ address */
2116c6fd2807SJeff Garzik 	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
2117c6fd2807SJeff Garzik 
2118c6fd2807SJeff Garzik 	/* unused: */
21198d9db2d2SRandy Dunlap 	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
2120c6fd2807SJeff Garzik 
2121c6fd2807SJeff Garzik 	/* Clear any currently outstanding port interrupt conditions */
2122c6fd2807SJeff Garzik 	serr_ofs = mv_scr_offset(SCR_ERROR);
2123c6fd2807SJeff Garzik 	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
2124c6fd2807SJeff Garzik 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2125c6fd2807SJeff Garzik 
2126c6fd2807SJeff Garzik 	/* unmask all EDMA error interrupts */
2127c6fd2807SJeff Garzik 	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
2128c6fd2807SJeff Garzik 
2129c6fd2807SJeff Garzik 	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
2130c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_CFG_OFS),
2131c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
2132c6fd2807SJeff Garzik 		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
2133c6fd2807SJeff Garzik }
2134c6fd2807SJeff Garzik 
21354447d351STejun Heo static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2136c6fd2807SJeff Garzik {
21374447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
21384447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2139c6fd2807SJeff Garzik 	u8 rev_id;
2140c6fd2807SJeff Garzik 	u32 hp_flags = hpriv->hp_flags;
2141c6fd2807SJeff Garzik 
2142c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
2143c6fd2807SJeff Garzik 
2144c6fd2807SJeff Garzik 	switch(board_idx) {
2145c6fd2807SJeff Garzik 	case chip_5080:
2146c6fd2807SJeff Garzik 		hpriv->ops = &mv5xxx_ops;
2147c6fd2807SJeff Garzik 		hp_flags |= MV_HP_50XX;
2148c6fd2807SJeff Garzik 
2149c6fd2807SJeff Garzik 		switch (rev_id) {
2150c6fd2807SJeff Garzik 		case 0x1:
2151c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB0;
2152c6fd2807SJeff Garzik 			break;
2153c6fd2807SJeff Garzik 		case 0x3:
2154c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2155c6fd2807SJeff Garzik 			break;
2156c6fd2807SJeff Garzik 		default:
2157c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2158c6fd2807SJeff Garzik 			   "Applying 50XXB2 workarounds to unknown rev\n");
2159c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2160c6fd2807SJeff Garzik 			break;
2161c6fd2807SJeff Garzik 		}
2162c6fd2807SJeff Garzik 		break;
2163c6fd2807SJeff Garzik 
2164c6fd2807SJeff Garzik 	case chip_504x:
2165c6fd2807SJeff Garzik 	case chip_508x:
2166c6fd2807SJeff Garzik 		hpriv->ops = &mv5xxx_ops;
2167c6fd2807SJeff Garzik 		hp_flags |= MV_HP_50XX;
2168c6fd2807SJeff Garzik 
2169c6fd2807SJeff Garzik 		switch (rev_id) {
2170c6fd2807SJeff Garzik 		case 0x0:
2171c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB0;
2172c6fd2807SJeff Garzik 			break;
2173c6fd2807SJeff Garzik 		case 0x3:
2174c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2175c6fd2807SJeff Garzik 			break;
2176c6fd2807SJeff Garzik 		default:
2177c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2178c6fd2807SJeff Garzik 			   "Applying B2 workarounds to unknown rev\n");
2179c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_50XXB2;
2180c6fd2807SJeff Garzik 			break;
2181c6fd2807SJeff Garzik 		}
2182c6fd2807SJeff Garzik 		break;
2183c6fd2807SJeff Garzik 
2184c6fd2807SJeff Garzik 	case chip_604x:
2185c6fd2807SJeff Garzik 	case chip_608x:
2186c6fd2807SJeff Garzik 		hpriv->ops = &mv6xxx_ops;
2187c6fd2807SJeff Garzik 
2188c6fd2807SJeff Garzik 		switch (rev_id) {
2189c6fd2807SJeff Garzik 		case 0x7:
2190c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1B2;
2191c6fd2807SJeff Garzik 			break;
2192c6fd2807SJeff Garzik 		case 0x9:
2193c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2194c6fd2807SJeff Garzik 			break;
2195c6fd2807SJeff Garzik 		default:
2196c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2197c6fd2807SJeff Garzik 				   "Applying B2 workarounds to unknown rev\n");
2198c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1B2;
2199c6fd2807SJeff Garzik 			break;
2200c6fd2807SJeff Garzik 		}
2201c6fd2807SJeff Garzik 		break;
2202c6fd2807SJeff Garzik 
2203c6fd2807SJeff Garzik 	case chip_7042:
2204c6fd2807SJeff Garzik 	case chip_6042:
2205c6fd2807SJeff Garzik 		hpriv->ops = &mv6xxx_ops;
2206c6fd2807SJeff Garzik 
2207c6fd2807SJeff Garzik 		hp_flags |= MV_HP_GEN_IIE;
2208c6fd2807SJeff Garzik 
2209c6fd2807SJeff Garzik 		switch (rev_id) {
2210c6fd2807SJeff Garzik 		case 0x0:
2211c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_XX42A0;
2212c6fd2807SJeff Garzik 			break;
2213c6fd2807SJeff Garzik 		case 0x1:
2214c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2215c6fd2807SJeff Garzik 			break;
2216c6fd2807SJeff Garzik 		default:
2217c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
2218c6fd2807SJeff Garzik 			   "Applying 60X1C0 workarounds to unknown rev\n");
2219c6fd2807SJeff Garzik 			hp_flags |= MV_HP_ERRATA_60X1C0;
2220c6fd2807SJeff Garzik 			break;
2221c6fd2807SJeff Garzik 		}
2222c6fd2807SJeff Garzik 		break;
2223c6fd2807SJeff Garzik 
2224c6fd2807SJeff Garzik 	default:
2225c6fd2807SJeff Garzik 		printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
2226c6fd2807SJeff Garzik 		return 1;
2227c6fd2807SJeff Garzik 	}
2228c6fd2807SJeff Garzik 
2229c6fd2807SJeff Garzik 	hpriv->hp_flags = hp_flags;
2230c6fd2807SJeff Garzik 
2231c6fd2807SJeff Garzik 	return 0;
2232c6fd2807SJeff Garzik }
2233c6fd2807SJeff Garzik 
2234c6fd2807SJeff Garzik /**
2235c6fd2807SJeff Garzik  *      mv_init_host - Perform some early initialization of the host.
22364447d351STejun Heo  *	@host: ATA host to initialize
22374447d351STejun Heo  *      @board_idx: controller index
2238c6fd2807SJeff Garzik  *
2239c6fd2807SJeff Garzik  *      If possible, do an early global reset of the host.  Then do
2240c6fd2807SJeff Garzik  *      our port init and clear/unmask all/relevant host interrupts.
2241c6fd2807SJeff Garzik  *
2242c6fd2807SJeff Garzik  *      LOCKING:
2243c6fd2807SJeff Garzik  *      Inherited from caller.
2244c6fd2807SJeff Garzik  */
22454447d351STejun Heo static int mv_init_host(struct ata_host *host, unsigned int board_idx)
2246c6fd2807SJeff Garzik {
2247c6fd2807SJeff Garzik 	int rc = 0, n_hc, port, hc;
22484447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
22494447d351STejun Heo 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
22504447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2251c6fd2807SJeff Garzik 
2252c6fd2807SJeff Garzik 	/* global interrupt mask */
2253c6fd2807SJeff Garzik 	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
2254c6fd2807SJeff Garzik 
22554447d351STejun Heo 	rc = mv_chip_id(host, board_idx);
2256c6fd2807SJeff Garzik 	if (rc)
2257c6fd2807SJeff Garzik 		goto done;
2258c6fd2807SJeff Garzik 
22594447d351STejun Heo 	n_hc = mv_get_hc_count(host->ports[0]->flags);
2260c6fd2807SJeff Garzik 
22614447d351STejun Heo 	for (port = 0; port < host->n_ports; port++)
2262c6fd2807SJeff Garzik 		hpriv->ops->read_preamp(hpriv, port, mmio);
2263c6fd2807SJeff Garzik 
2264c6fd2807SJeff Garzik 	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
2265c6fd2807SJeff Garzik 	if (rc)
2266c6fd2807SJeff Garzik 		goto done;
2267c6fd2807SJeff Garzik 
2268c6fd2807SJeff Garzik 	hpriv->ops->reset_flash(hpriv, mmio);
2269c6fd2807SJeff Garzik 	hpriv->ops->reset_bus(pdev, mmio);
2270c6fd2807SJeff Garzik 	hpriv->ops->enable_leds(hpriv, mmio);
2271c6fd2807SJeff Garzik 
22724447d351STejun Heo 	for (port = 0; port < host->n_ports; port++) {
2273c6fd2807SJeff Garzik 		if (IS_60XX(hpriv)) {
2274c6fd2807SJeff Garzik 			void __iomem *port_mmio = mv_port_base(mmio, port);
2275c6fd2807SJeff Garzik 
2276c6fd2807SJeff Garzik 			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2277c6fd2807SJeff Garzik 			ifctl |= (1 << 7);		/* enable gen2i speed */
2278c6fd2807SJeff Garzik 			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2279c6fd2807SJeff Garzik 			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2280c6fd2807SJeff Garzik 		}
2281c6fd2807SJeff Garzik 
2282c6fd2807SJeff Garzik 		hpriv->ops->phy_errata(hpriv, mmio, port);
2283c6fd2807SJeff Garzik 	}
2284c6fd2807SJeff Garzik 
22854447d351STejun Heo 	for (port = 0; port < host->n_ports; port++) {
2286c6fd2807SJeff Garzik 		void __iomem *port_mmio = mv_port_base(mmio, port);
22874447d351STejun Heo 		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
2288c6fd2807SJeff Garzik 	}
2289c6fd2807SJeff Garzik 
2290c6fd2807SJeff Garzik 	for (hc = 0; hc < n_hc; hc++) {
2291c6fd2807SJeff Garzik 		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2292c6fd2807SJeff Garzik 
2293c6fd2807SJeff Garzik 		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
2294c6fd2807SJeff Garzik 			"(before clear)=0x%08x\n", hc,
2295c6fd2807SJeff Garzik 			readl(hc_mmio + HC_CFG_OFS),
2296c6fd2807SJeff Garzik 			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
2297c6fd2807SJeff Garzik 
2298c6fd2807SJeff Garzik 		/* Clear any currently outstanding hc interrupt conditions */
2299c6fd2807SJeff Garzik 		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
2300c6fd2807SJeff Garzik 	}
2301c6fd2807SJeff Garzik 
2302c6fd2807SJeff Garzik 	/* Clear any currently outstanding host interrupt conditions */
2303c6fd2807SJeff Garzik 	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
2304c6fd2807SJeff Garzik 
2305c6fd2807SJeff Garzik 	/* and unmask interrupt generation for host regs */
2306c6fd2807SJeff Garzik 	writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
2307fb621e2fSJeff Garzik 
2308fb621e2fSJeff Garzik 	if (IS_50XX(hpriv))
2309fb621e2fSJeff Garzik 		writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2310fb621e2fSJeff Garzik 	else
2311c6fd2807SJeff Garzik 		writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
2312c6fd2807SJeff Garzik 
2313c6fd2807SJeff Garzik 	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
2314c6fd2807SJeff Garzik 		"PCI int cause/mask=0x%08x/0x%08x\n",
2315c6fd2807SJeff Garzik 		readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
2316c6fd2807SJeff Garzik 		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
2317c6fd2807SJeff Garzik 		readl(mmio + PCI_IRQ_CAUSE_OFS),
2318c6fd2807SJeff Garzik 		readl(mmio + PCI_IRQ_MASK_OFS));
2319c6fd2807SJeff Garzik 
2320c6fd2807SJeff Garzik done:
2321c6fd2807SJeff Garzik 	return rc;
2322c6fd2807SJeff Garzik }
2323c6fd2807SJeff Garzik 
2324c6fd2807SJeff Garzik /**
2325c6fd2807SJeff Garzik  *      mv_print_info - Dump key info to kernel log for perusal.
23264447d351STejun Heo  *      @host: ATA host to print info about
2327c6fd2807SJeff Garzik  *
2328c6fd2807SJeff Garzik  *      FIXME: complete this.
2329c6fd2807SJeff Garzik  *
2330c6fd2807SJeff Garzik  *      LOCKING:
2331c6fd2807SJeff Garzik  *      Inherited from caller.
2332c6fd2807SJeff Garzik  */
23334447d351STejun Heo static void mv_print_info(struct ata_host *host)
2334c6fd2807SJeff Garzik {
23354447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
23364447d351STejun Heo 	struct mv_host_priv *hpriv = host->private_data;
2337c6fd2807SJeff Garzik 	u8 rev_id, scc;
2338c6fd2807SJeff Garzik 	const char *scc_s;
2339c6fd2807SJeff Garzik 
2340c6fd2807SJeff Garzik 	/* Use this to determine the HW stepping of the chip so we know
2341c6fd2807SJeff Garzik 	 * what errata to workaround
2342c6fd2807SJeff Garzik 	 */
2343c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
2344c6fd2807SJeff Garzik 
2345c6fd2807SJeff Garzik 	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
2346c6fd2807SJeff Garzik 	if (scc == 0)
2347c6fd2807SJeff Garzik 		scc_s = "SCSI";
2348c6fd2807SJeff Garzik 	else if (scc == 0x01)
2349c6fd2807SJeff Garzik 		scc_s = "RAID";
2350c6fd2807SJeff Garzik 	else
2351c6fd2807SJeff Garzik 		scc_s = "unknown";
2352c6fd2807SJeff Garzik 
2353c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2354c6fd2807SJeff Garzik 	       "%u slots %u ports %s mode IRQ via %s\n",
23554447d351STejun Heo 	       (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
2356c6fd2807SJeff Garzik 	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
2357c6fd2807SJeff Garzik }
2358c6fd2807SJeff Garzik 
2359c6fd2807SJeff Garzik /**
2360c6fd2807SJeff Garzik  *      mv_init_one - handle a positive probe of a Marvell host
2361c6fd2807SJeff Garzik  *      @pdev: PCI device found
2362c6fd2807SJeff Garzik  *      @ent: PCI device ID entry for the matched host
2363c6fd2807SJeff Garzik  *
2364c6fd2807SJeff Garzik  *      LOCKING:
2365c6fd2807SJeff Garzik  *      Inherited from caller.
2366c6fd2807SJeff Garzik  */
2367c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2368c6fd2807SJeff Garzik {
2369c6fd2807SJeff Garzik 	static int printed_version = 0;
2370c6fd2807SJeff Garzik 	unsigned int board_idx = (unsigned int)ent->driver_data;
23714447d351STejun Heo 	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
23724447d351STejun Heo 	struct ata_host *host;
23734447d351STejun Heo 	struct mv_host_priv *hpriv;
23744447d351STejun Heo 	int n_ports, rc;
2375c6fd2807SJeff Garzik 
2376c6fd2807SJeff Garzik 	if (!printed_version++)
2377c6fd2807SJeff Garzik 		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
2378c6fd2807SJeff Garzik 
23794447d351STejun Heo 	/* allocate host */
23804447d351STejun Heo 	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
23814447d351STejun Heo 
23824447d351STejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
23834447d351STejun Heo 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
23844447d351STejun Heo 	if (!host || !hpriv)
23854447d351STejun Heo 		return -ENOMEM;
23864447d351STejun Heo 	host->private_data = hpriv;
23874447d351STejun Heo 
23884447d351STejun Heo 	/* acquire resources */
238924dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
239024dc5f33STejun Heo 	if (rc)
2391c6fd2807SJeff Garzik 		return rc;
2392c6fd2807SJeff Garzik 
23930d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
23940d5ff566STejun Heo 	if (rc == -EBUSY)
239524dc5f33STejun Heo 		pcim_pin_device(pdev);
23960d5ff566STejun Heo 	if (rc)
239724dc5f33STejun Heo 		return rc;
23984447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
2399c6fd2807SJeff Garzik 
2400d88184fbSJeff Garzik 	rc = pci_go_64(pdev);
2401d88184fbSJeff Garzik 	if (rc)
2402d88184fbSJeff Garzik 		return rc;
2403d88184fbSJeff Garzik 
2404c6fd2807SJeff Garzik 	/* initialize adapter */
24054447d351STejun Heo 	rc = mv_init_host(host, board_idx);
240624dc5f33STejun Heo 	if (rc)
240724dc5f33STejun Heo 		return rc;
2408c6fd2807SJeff Garzik 
2409c6fd2807SJeff Garzik 	/* Enable interrupts */
24106a59dcf8STejun Heo 	if (msi && pci_enable_msi(pdev))
2411c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
2412c6fd2807SJeff Garzik 
2413c6fd2807SJeff Garzik 	mv_dump_pci_cfg(pdev, 0x68);
24144447d351STejun Heo 	mv_print_info(host);
2415c6fd2807SJeff Garzik 
24164447d351STejun Heo 	pci_set_master(pdev);
24174447d351STejun Heo 	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
24184447d351STejun Heo 				 &mv_sht);
2419c6fd2807SJeff Garzik }
2420c6fd2807SJeff Garzik 
2421c6fd2807SJeff Garzik static int __init mv_init(void)
2422c6fd2807SJeff Garzik {
2423c6fd2807SJeff Garzik 	return pci_register_driver(&mv_pci_driver);
2424c6fd2807SJeff Garzik }
2425c6fd2807SJeff Garzik 
2426c6fd2807SJeff Garzik static void __exit mv_exit(void)
2427c6fd2807SJeff Garzik {
2428c6fd2807SJeff Garzik 	pci_unregister_driver(&mv_pci_driver);
2429c6fd2807SJeff Garzik }
2430c6fd2807SJeff Garzik 
2431c6fd2807SJeff Garzik MODULE_AUTHOR("Brett Russ");
2432c6fd2807SJeff Garzik MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
2433c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2434c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
2435c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2436c6fd2807SJeff Garzik 
2437c6fd2807SJeff Garzik module_param(msi, int, 0444);
2438c6fd2807SJeff Garzik MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2439c6fd2807SJeff Garzik 
2440c6fd2807SJeff Garzik module_init(mv_init);
2441c6fd2807SJeff Garzik module_exit(mv_exit);
2442