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