sata_mv.c revision da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9d
120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ/*
220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * sata_mv.c - Marvell SATA support
320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
48b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik * Copyright 2005: EMC Corporation, all rights reserved.
5e2b1be56c5656902744c2b52e8304126a40bb609Jeff Garzik * Copyright 2005 Red Hat, Inc.  All rights reserved.
620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * This program is free software; you can redistribute it and/or modify
1020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * it under the terms of the GNU General Public License as published by
1120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * the Free Software Foundation; version 2 of the License.
1220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
1320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * This program is distributed in the hope that it will be useful,
1420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * GNU General Public License for more details.
1720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
1820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * You should have received a copy of the GNU General Public License
1920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * along with this program; if not, write to the Free Software
2020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ *
2220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ */
2320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
244a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik/*
254a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  sata_mv TODO list:
264a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
274a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  1) Needs a full errata audit for all chipsets.  I implemented most
284a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  of the errata workarounds found in the Marvell vendor driver, but
294a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  I distinctly remember a couple workarounds (one related to PCI-X)
304a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  are still needed.
314a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
324a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  4) Add NCQ support (easy to intermediate, once new-EH support appears)
334a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
344a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  5) Investigate problems with PCI Message Signalled Interrupts (MSI).
354a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
364a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  6) Add port multiplier support (intermediate)
374a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
384a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  8) Develop a low-power-consumption strategy, and implement it.
394a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
404a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  9) [Experiment, low priority] See if ATAPI can be supported using
414a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  "unknown FIS" or "vendor-specific FIS" support, or something creative
424a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  like that.
434a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
444a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  10) [Experiment, low priority] Investigate interrupt coalescing.
454a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  Quite often, especially with PCI Message Signalled Interrupts (MSI),
464a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  the overhead reduced by interrupt mitigation is quite often not
474a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  worth the latency cost.
484a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
494a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  11) [Experiment, Marvell value added] Is it possible to use target
504a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  mode to cross-connect two Linux boxes with Marvell cards?  If so,
514a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  creating LibATA target mode support would be very interesting.
524a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
534a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  Target mode, for those without docs, is the ability to directly
544a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  connect two SATA controllers.
554a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
564a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  13) Verify that 7042 is fully supported.  I only have a 6042.
574a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
584a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik*/
594a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
604a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
6120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/kernel.h>
6220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/module.h>
6320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/pci.h>
6420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/init.h>
6520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/blkdev.h>
6620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/delay.h>
6720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/interrupt.h>
6820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/dma-mapping.h>
69a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik#include <linux/device.h>
7020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <scsi/scsi_host.h>
71193515d51ccb363165d6b09e9ba5c21089e34badJeff Garzik#include <scsi/scsi_cmnd.h>
7220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/libata.h>
7320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
7420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#define DRV_NAME	"sata_mv"
758bc3fc470eb25af4d70c72485cbcb130cc657691Jeff Garzik#define DRV_VERSION	"0.81"
7620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
7720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russenum {
7820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* BAR's are enumerated in terms of pci_resource_start() terms */
7920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */
8020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IO_BAR		= 2,	/* offset 0x18: IO space */
8120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */
8220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */
8420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */
8520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_BASE		= 0,
8720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
88615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
89615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
90615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
91615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
92615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
93615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
9420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC0_REG_BASE	= 0x20000,
95522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_FLASH_CTL		= 0x1046c,
96bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_GPIO_PORT_CTL	= 0x104f0,
97bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_RESET_CFG		= 0x180d8,
9820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
9920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,
10020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,
10120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
10220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
10320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
10431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH		= 32,
10531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
10631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
10831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * CRPB needs alignment on a 256B boundary. Size == 256B
10931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
11031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
11131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
11231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
11331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
11431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_SG_CT		= 176,
11531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
11631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
11731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORTS_PER_HC		= 4,
11920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
12020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_HC_SHIFT	= 2,
12131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
12220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_MASK		= 3,
12320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
12420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Host Flags */
12520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
12620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
127c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	MV_COMMON_FLAGS		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
128bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
129bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_PIO_POLLING,
13047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,
13120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
13231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_FLAG_READ		= (1 << 0),
13331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_TAG_SHIFT		= 1,
134c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_IOID_SHIFT		= 6,	/* CRQB Gen-II/IIE IO Id shift */
135c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_HOSTQ_SHIFT	= 17,	/* CRQB Gen-II/IIE HostQueTag shift */
13631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_ADDR_SHIFT	= 8,
13731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_CS		= (0x2 << 11),
13831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_LAST		= (1 << 15),
13931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_FLAG_STATUS_SHIFT	= 8,
141c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_6	= 5,	/* CRPB Gen-II IO Id shift */
142c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_7	= 7,	/* CRPB Gen-IIE IO Id shift */
14331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EPRD_FLAG_END_OF_TBL	= (1 << 31),
14531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* PCI interface registers */
14720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
14831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	PCI_COMMAND_OFS		= 0xc00,
14931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
15020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MAIN_CMD_STS_OFS	= 0xd30,
15120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	STOP_PCI_MASTER		= (1 << 2),
15220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MASTER_EMPTY	= (1 << 3),
15320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GLOB_SFT_RST		= (1 << 4),
15420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
155522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MODE		= 0xd00,
156522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,
157522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_DISC_TIMER	= 0xd04,
158522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MSI_TRIGGER	= 0xc38,
159522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_SERR_MASK	= 0xc28,
160522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_XBAR_TMOUT	= 0x1d04,
161522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,
162522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,
163522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,
164522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_COMMAND	= 0x1d50,
165522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
166522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	PCI_IRQ_CAUSE_OFS		= 0x1d58,
167522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	PCI_IRQ_MASK_OFS		= 0x1d5c,
16820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
16920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
17020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
17120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
17220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_ERR		= (1 << 0),	/* shift by port # */
17320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_DONE		= (1 << 1),	/* shift by port # */
17420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
17520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
17620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_ERR			= (1 << 18),
17720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
17820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
179fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_0_3_COAL_DONE	= (1 << 8),
180fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_4_7_COAL_DONE	= (1 << 17),
18120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
18220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GPIO_INT		= (1 << 22),
18320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SELF_INT		= (1 << 23),
18420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TWSI_INT		= (1 << 24),
18520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
186fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
1878b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
18820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
18920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   HC_MAIN_RSVD),
190fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
191fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik				   HC_MAIN_RSVD_5),
19220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
19320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATAHC registers */
19420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_CFG_OFS		= 0,
19520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
19620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_CAUSE_OFS	= 0x14,
19731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
19820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
19920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	DEV_IRQ			= (1 << 8),	/* shift by port # */
20020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Shadow block registers */
20231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_BLK_OFS		= 0x100,
20331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
20420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATA registers */
20620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
20720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_ACTIVE_OFS		= 0x350,
20847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	PHY_MODE3		= 0x310,
209bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE4		= 0x314,
210bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE2		= 0x330,
211c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_MODE		= 0x74,
212c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_LT_MODE		= 0x30,
213c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_CTL		= 0x0C,
214bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	SATA_INTERFACE_CTL	= 0x050,
215bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
216bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_M2_PREAMP_MASK	= 0x7e0,
21720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Port registers */
21920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_CFG_OFS		= 0,
22031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
22131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ		= (1 << 5),
22231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
22331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
22431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
22520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
22620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
22720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
2286c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
2296c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
2306c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV		= (1 << 2),	/* device error */
2316c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
2326c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
2336c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
234c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
235c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
2366c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
237c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
2386c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
2396c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
2406c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
2416c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
2426c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
24320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
2446c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
2456c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
2466c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
2476c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
248c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_OVERRUN_5	= (1 << 5),
249c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_UNDERRUN_5	= (1 << 6),
250bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
251bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
252bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
253bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
254bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SERR |
255bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS |
2566c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
257bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
258bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
259bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY |
260bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_CTRL_RX_2 |
261bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_RX |
262bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_TX |
263bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_TRANS_PROTO,
264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE_5	= EDMA_ERR_D_PAR |
265bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
266bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
267bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
268bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_OVERRUN_5 |
269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_UNDERRUN_5 |
270bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS_5 |
2716c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
272bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
273bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
274bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY,
27520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
27731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
27831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
27931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
28031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_PTR_SHIFT	= 5,
28131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
28231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
28331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
28431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
28531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_PTR_SHIFT	= 3,
28631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2870ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
2880ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_EN			= (1 << 0),	/* enable EDMA */
2890ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
2900ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
29120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
292c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	EDMA_IORDY_TMOUT	= 0x34,
293bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	EDMA_ARB_CFG		= 0x38,
294bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
29531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Host private flags (hp_flags) */
29631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_HP_FLAG_MSI		= (1 << 0),
29747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB0	= (1 << 1),
29847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB2	= (1 << 2),
29947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1B2	= (1 << 3),
30047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1C0	= (1 << 4),
301e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	MV_HP_ERRATA_XX42A0	= (1 << 5),
3020ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
3030ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
3040ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
30520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
30631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Port private flags (pp_flags) */
3070ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
3080ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
30920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
31020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
311ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
312ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
313e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
314bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
315095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzikenum {
316d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	MV_DMA_BOUNDARY		= 0xffffffffU,
317095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3180ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* mask of register bits containing lower 32 bits
3190ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 * of EDMA request queue DMA address
3200ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 */
321095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
322095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3230ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* ditto, for response queue */
324095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
325095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik};
326095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
327522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikenum chip_type {
328522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_504x,
329522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_508x,
330522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_5080,
331522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_604x,
332522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_608x,
333e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_6042,
334e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_7042,
335522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik};
336522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
33731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ReQuest Block: 32B */
33831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crqb {
339e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr;
340e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr_hi;
341e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ctrl_flags;
342e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ata_cmd[11];
34331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
34420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
345e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstruct mv_crqb_iie {
346e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
347e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
348e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags;
349e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			len;
350e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			ata_cmd[4];
351e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
352e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
35331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ResPonse Block: 8B */
35431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crpb {
355e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			id;
356e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			flags;
357e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			tmstmp;
35820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
35920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
36031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
36131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_sg {
362e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
363e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags_size;
364e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
365e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			reserved;
36631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
36720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
36831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_port_priv {
36931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crqb		*crqb;
37031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crqb_dma;
37131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crpb		*crpb;
37231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crpb_dma;
37331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_sg		*sg_tbl;
37431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		sg_tbl_dma;
375bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
376bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		req_idx;
377bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		resp_idx;
378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
37931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			pp_flags;
38031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
38131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
382bca1c4eb9411533d613123618c0d127fae532595Jeff Garzikstruct mv_port_signal {
383bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			amps;
384bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			pre;
385bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik};
386bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
38747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_host_priv;
38847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_hw_ops {
3892a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
3902a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
39147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
39247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
39347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
394c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
395c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
396522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
397522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
39847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
39947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
40031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_host_priv {
40131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			hp_flags;
402bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	struct mv_port_signal	signal[8];
40347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	const struct mv_hw_ops	*ops;
40420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
40520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
40620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void mv_irq_clear(struct ata_port *ap);
407da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
408da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
409da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
410da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
41131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap);
41231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap);
41331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc);
414e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc);
4159a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
416bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap);
417bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc);
418bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap);
419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap);
42020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
42120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
4222a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4232a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
42447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
42547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
42647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
427c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
428c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
429522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
430522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
43147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
4322a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4332a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
43447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
43547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
43647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
437c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
438c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
439522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
440522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
441c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
442c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no);
44347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
444c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv5_sht = {
445c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.module			= THIS_MODULE,
446c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.name			= DRV_NAME,
447c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.ioctl			= ata_scsi_ioctl,
448c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.queuecommand		= ata_scsi_queuecmd,
449c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
450c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.this_id		= ATA_SHT_THIS_ID,
451c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT,
452c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
453c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.emulated		= ATA_SHT_EMULATED,
454c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.use_clustering		= 1,
455c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.proc_name		= DRV_NAME,
456c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.dma_boundary		= MV_DMA_BOUNDARY,
457c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.slave_configure	= ata_scsi_slave_config,
458c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.slave_destroy		= ata_scsi_slave_destroy,
459c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.bios_param		= ata_std_bios_param,
460c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik};
461c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
462c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv6_sht = {
46320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.module			= THIS_MODULE,
46420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
46520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.ioctl			= ata_scsi_ioctl,
46620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.queuecommand		= ata_scsi_queuecmd,
467c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
46820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.this_id		= ATA_SHT_THIS_ID,
469d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT,
47020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
47120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.emulated		= ATA_SHT_EMULATED,
472d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	.use_clustering		= 1,
47320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.proc_name		= DRV_NAME,
47420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dma_boundary		= MV_DMA_BOUNDARY,
47520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.slave_configure	= ata_scsi_slave_config,
476ccf68c3405fca11386004674377d951b9b18e756Tejun Heo	.slave_destroy		= ata_scsi_slave_destroy,
47720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.bios_param		= ata_std_bios_param,
47820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
47920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
480c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv5_ops = {
481c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_disable		= ata_port_disable,
482c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
483c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_load		= ata_tf_load,
484c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_read		= ata_tf_read,
485c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.check_status		= ata_check_status,
486c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.exec_command		= ata_exec_command,
487c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.dev_select		= ata_std_dev_select,
488c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
489cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
490c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
491c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_prep		= mv_qc_prep,
492c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_issue		= mv_qc_issue,
4930d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
494c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
495c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.irq_clear		= mv_irq_clear,
496246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
497246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
498c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
499bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
502bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
504c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_read		= mv5_scr_read,
505c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_write		= mv5_scr_write,
506c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
507c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_start		= mv_port_start,
508c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_stop		= mv_port_stop,
509c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik};
510c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
511c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv6_ops = {
51220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.port_disable		= ata_port_disable,
51320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
51420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_load		= ata_tf_load,
51520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_read		= ata_tf_read,
51620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.check_status		= ata_check_status,
51720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.exec_command		= ata_exec_command,
51820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dev_select		= ata_std_dev_select,
51920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
520cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
52120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
52231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_prep		= mv_qc_prep,
52331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_issue		= mv_qc_issue,
5240d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
52520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
52620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.irq_clear		= mv_irq_clear,
527246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
528246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
52920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
530bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
531bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
532bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
533bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
534bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
53520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_read		= mv_scr_read,
53620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_write		= mv_scr_write,
53720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
53831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_start		= mv_port_start,
53931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_stop		= mv_port_stop,
54020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
54120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
542e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic const struct ata_port_operations mv_iie_ops = {
543e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_disable		= ata_port_disable,
544e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
545e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_load		= ata_tf_load,
546e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_read		= ata_tf_read,
547e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.check_status		= ata_check_status,
548e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.exec_command		= ata_exec_command,
549e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.dev_select		= ata_std_dev_select,
550e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
551cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
552e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
553e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_prep		= mv_qc_prep_iie,
554e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_issue		= mv_qc_issue,
5550d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
556e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
557e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.irq_clear		= mv_irq_clear,
558246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
559246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
560e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
561bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
562bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
565bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
566e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_read		= mv_scr_read,
567e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_write		= mv_scr_write,
568e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
569e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_start		= mv_port_start,
570e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_stop		= mv_port_stop,
571e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
572e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
57398ac62defe529d04a192688f40d801a2d8fbcf98Arjan van de Venstatic const struct ata_port_info mv_port_info[] = {
57420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_504x */
575cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= MV_COMMON_FLAGS,
57631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
577bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
578c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
57920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
58020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_508x */
581c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
58231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
583bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
584c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
58520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
58647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	{  /* chip_5080 */
587c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
58847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
589bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
590c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
59147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	},
59220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_604x */
593c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
59431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
595bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
596c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
59720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
59820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_608x */
599c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
600c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				  MV_FLAG_DUAL_HC,
60131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
602bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
603c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
60420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
605e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_6042 */
606c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
607e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
608bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
609e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
610e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
611e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_7042 */
612c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
613e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
614bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
615e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
616e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
61720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
61820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
6193b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id mv_pci_tbl[] = {
6202d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
6212d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
6222d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
6232d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
6242d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6252d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
6262d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
6272d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
6282d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
6292d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
6302d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6312d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
6322d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
633d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	/* Adaptec 1430SA */
634d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
635d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger
636e93f09dc2d49d8e98818a93ad17f3ede91533738Olof Johansson	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
637e93f09dc2d49d8e98818a93ad17f3ede91533738Olof Johansson
6386a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	/* add Marvell 7042 support */
6396a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
6406a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom
6412d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ }			/* terminate list */
64220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
64320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
64420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic struct pci_driver mv_pci_driver = {
64520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
64620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.id_table		= mv_pci_tbl,
64720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.probe			= mv_init_one,
64820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.remove			= ata_pci_remove_one,
64920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
65020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
65147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv5xxx_ops = {
65247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv5_phy_errata,
65347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv5_enable_leds,
65447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv5_read_preamp,
65547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv5_reset_hc,
656522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv5_reset_flash,
657522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv5_reset_bus,
65847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
65947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
66047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv6xxx_ops = {
66147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv6_phy_errata,
66247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv6_enable_leds,
66347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv6_read_preamp,
66447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv6_reset_hc,
665522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv6_reset_flash,
666522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv_reset_pci_bus,
66747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
66847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
66920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ/*
670ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik * module options
671ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik */
672ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikstatic int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
673ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
674ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
675d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik/* move to PCI layer or libata core? */
676d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzikstatic int pci_go_64(struct pci_dev *pdev)
677d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik{
678d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	int rc;
679d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
680d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
681d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
682d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
683d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
684d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			if (rc) {
685d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				dev_printk(KERN_ERR, &pdev->dev,
686d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik					   "64-bit DMA enable failed\n");
687d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				return rc;
688d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			}
689d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
690d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	} else {
691d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
692d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
693d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
694d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit DMA enable failed\n");
695d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
696d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
697d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
698d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
699d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
700d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit consistent DMA enable failed\n");
701d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
702d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
703d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	}
704d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
705d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	return rc;
706d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik}
707d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
708ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik/*
70920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Functions
71020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ */
71120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
71220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void writelfl(unsigned long data, void __iomem *addr)
71320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
71420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writel(data, addr);
71520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	(void) readl(addr);	/* flush to avoid PCI posted write */
71620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
71720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
71820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
71920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
72120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
72220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
723c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hc_from_port(unsigned int port)
724c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
725c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port >> MV_PORT_HC_SHIFT;
726c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
727c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
728c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hardport_from_port(unsigned int port)
729c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
730c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port & MV_PORT_MASK;
731c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
732c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
733c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline void __iomem *mv_hc_base_from_port(void __iomem *base,
734c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik						 unsigned int port)
735c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
736c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return mv_hc_base(base, mv_hc_from_port(port));
737c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
738c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
73920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
74020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
741c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return  mv_hc_base_from_port(base, port) +
7428b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		MV_SATAHC_ARBTR_REG_SZ +
743c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
74420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
74520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
74620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_ap_base(struct ata_port *ap)
74720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
7480d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
74920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
751cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic inline int mv_get_hc_count(unsigned long port_flags)
75231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
753cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
75431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
75531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
75631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_irq_clear(struct ata_port *ap)
75720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
75820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
760c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_set_edma_ptrs(void __iomem *port_mmio,
761c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_host_priv *hpriv,
762c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_port_priv *pp)
763c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik{
764bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 index;
765bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
766c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
767c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize request queue
768c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
769bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
770bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
771c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crqb_dma & 0x3ff);
772c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
773bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
774c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
775c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
776c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
777bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crqb_dma & 0xffffffff) | index,
778c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
779c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
780bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
781c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
782c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
783c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize response queue
784c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
785bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
786bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
787c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crpb_dma & 0xff);
788c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
789c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
790c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
791bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & 0xffffffff) | index,
792c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
793c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
794bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
795c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
796bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
797c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
798c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik}
799c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
80005b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
80105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_start_dma - Enable eDMA engine
80205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @base: port base address
80305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pp: port private data
80405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
805beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
806beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
80705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
80805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
80905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
81005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
811c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
812c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 struct mv_port_priv *pp)
81320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
814c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
815bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* clear EDMA event indicators, if any */
816bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
817bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
818bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_set_edma_ptrs(base, hpriv, pp);
819bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
820afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
821afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
822afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
823beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
82420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
82520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
82605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
8270ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik *      __mv_stop_dma - Disable eDMA engine
82805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
82905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
830beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
831beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
83205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
83305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
83405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
83505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
8360ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int __mv_stop_dma(struct ata_port *ap)
83720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
83831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
83931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp	= ap->private_data;
84031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 reg;
841c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int i, err = 0;
84231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
8434537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
844afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		/* Disable EDMA if active.   The disable bit auto clears.
84531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
84631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
84731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
848afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	} else {
849beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
850afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ  	}
8518b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
85231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* now properly wait for the eDMA to stop */
85331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (i = 1000; i > 0; i--) {
85431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		reg = readl(port_mmio + EDMA_CMD_OFS);
8554537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		if (!(reg & EDMA_EN))
85631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
8574537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik
85831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		udelay(100);
85931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
86031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
861c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (reg & EDMA_EN) {
862f15a1dafed22d5037e0feea7528e1eeb28a1a7a3Tejun Heo		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
863c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		err = -EIO;
86431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
865c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
866c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	return err;
86720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
86820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8690ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int mv_stop_dma(struct ata_port *ap)
8700ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik{
8710ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
8720ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	int rc;
8730ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8740ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
8750ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	rc = __mv_stop_dma(ap);
8760ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
8770ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8780ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	return rc;
8790ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik}
8800ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8818a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#ifdef ATA_DEBUG
88231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_mem(void __iomem *start, unsigned bytes)
88320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
88431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
88531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
88631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%p: ", start + b);
88731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
88831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			printk("%08x ",readl(start + b));
88931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
89031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
89131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
89231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
89331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
8948a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#endif
8958a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik
89631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
89731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
89831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
89931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
90031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 dw;
90131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
90231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%02x: ", b);
90331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
90431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			(void) pci_read_config_dword(pdev,b,&dw);
90531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			printk("%08x ",dw);
90631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
90731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
90831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
90931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
91031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
91131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
91231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_all_regs(void __iomem *mmio_base, int port,
91331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			     struct pci_dev *pdev)
91431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
91531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
9168b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	void __iomem *hc_base = mv_hc_base(mmio_base,
91731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ					   port >> MV_PORT_HC_SHIFT);
91831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_base;
91931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int start_port, num_ports, p, start_hc, num_hcs, hc;
92031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
92131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (0 > port) {
92231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = start_port = 0;
92331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = 8;		/* shld be benign for 4 port devs */
92431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_hcs = 2;
92531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	} else {
92631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = port >> MV_PORT_HC_SHIFT;
92731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_port = port;
92831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = num_hcs = 1;
92931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
9308b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
93131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports > 1 ? num_ports - 1 : start_port);
93231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
93331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (NULL != pdev) {
93431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("PCI config space regs:\n");
93531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_pci_cfg(pdev, 0x68);
93631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
93731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	DPRINTK("PCI regs:\n");
93831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xc00, 0x3c);
93931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xd00, 0x34);
94031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xf00, 0x4);
94131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0x1d00, 0x6c);
94231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
943d220c37e0a3c9a47ae00e87e044d963b3ea040bcDan Aloni		hc_base = mv_hc_base(mmio_base, hc);
94431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("HC regs (HC %i):\n", hc);
94531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(hc_base, 0x1c);
94631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
94731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (p = start_port; p < start_port + num_ports; p++) {
94831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port_base = mv_port_base(mmio_base, p);
94931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("EDMA regs (port %i):\n",p);
95031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base, 0x54);
95131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("SATA regs (port %i):\n",p);
95231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base+0x300, 0x60);
95331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
95431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
95520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
95620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
95720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic unsigned int mv_scr_offset(unsigned int sc_reg_in)
95820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
95920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs;
96020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
96120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	switch (sc_reg_in) {
96220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_STATUS:
96320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_CONTROL:
96420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ERROR:
96520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
96620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
96720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ACTIVE:
96820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
96920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
97020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	default:
97120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = 0xffffffffU;
97220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
97320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
97420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return ofs;
97520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
97620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
977da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
97820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
97920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
98020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
981da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
982da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(mv_ap_base(ap) + ofs);
983da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
984da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
985da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
98620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
98720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
988da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
98920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
99020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
99120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
992da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
99320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		writelfl(val, mv_ap_base(ap) + ofs);
994da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
995da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
996da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
99720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
99820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
999c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
1000c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			void __iomem *port_mmio)
1001e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1002e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
1003e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1004e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* set up non-NCQ EDMA configuration */
1005c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	cfg &= ~(1 << 9);	/* disable eQue */
1006e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1007e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	if (IS_GEN_I(hpriv)) {
1008e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1009e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 8);	/* enab config burst size mask */
1010e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1011e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1012e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	else if (IS_GEN_II(hpriv)) {
1013e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1014e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
1015e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
1016e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1017e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1018e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	else if (IS_GEN_IIE(hpriv)) {
1019e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
1020e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
1021e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
1022e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 18);	/* enab early completion */
1023e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
1024e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
10254537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		cfg &= ~(EDMA_CFG_NCQ);	/* clear NCQ */
1026e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
1027e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1028e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
1029e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1030e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
103105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
103205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_start - Port specific init/start routine.
103305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
103405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
103505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Allocate and point to DMA memory, init port private memory,
103605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      zero indices.
103705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
103805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
103905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
104005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
104131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap)
104231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1043cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct device *dev = ap->host->dev;
1044cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
104531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp;
104631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
104731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void *mem;
104831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t mem_dma;
10490ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
105024dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	int rc;
105131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
105224dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
10536037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!pp)
105424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
105531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
105624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
105724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo				  GFP_KERNEL);
10586037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!mem)
105924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
106031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
106131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10626037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	rc = ata_pad_alloc(ap, dev);
10636037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (rc)
106424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
10656037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik
10668b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* First item in chunk of DMA memory:
106731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command request table (CRQB), 32 bytes each in size
106831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
106931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb = mem;
107031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb_dma = mem_dma;
107131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRQB_Q_SZ;
107231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRQB_Q_SZ;
107331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10748b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* Second item:
107531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command response table (CRPB), 8 bytes each in size
107631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
107731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb = mem;
107831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb_dma = mem_dma;
107931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRPB_Q_SZ;
108031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRPB_Q_SZ;
108131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
108231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Third item:
108331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
108431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
108531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl = mem;
108631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl_dma = mem_dma;
108731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10880ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
10890ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
1090c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_edma_cfg(ap, hpriv, port_mmio);
1091e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1092c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_set_edma_ptrs(port_mmio, hpriv, pp);
109331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10940ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
10950ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
109631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Don't turn on EDMA here...do it before DMA commands only.  Else
109731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * we'll be unable to send non-data, PIO, etc due to restricted access
109831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * to shadow regs.
109931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
110031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	ap->private_data = pp;
110131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
110231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
110331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
110405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
110505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_stop - Port specific cleanup/stop routine.
110605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
110705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
110805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Stop DMA, cleanup port memory.
110905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
111005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
1111cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine uses the host lock to protect the DMA stop.
111205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
111331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap)
111431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
111531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_stop_dma(ap);
111631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
111731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
111805b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
111905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
112005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command whose SG list to source from
112105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
112205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Populate the SG list and mark the last entry.
112305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
112405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
112505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
112605b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1127d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzikstatic unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
112831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
112931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = qc->ap->private_data;
1130d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	unsigned int n_sg = 0;
1131972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	struct scatterlist *sg;
1132d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	struct mv_sg *mv_sg;
113331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1134d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	mv_sg = pp->sg_tbl;
1135972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	ata_for_each_sg(sg, qc) {
1136d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		dma_addr_t addr = sg_dma_address(sg);
1137d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		u32 sg_len = sg_dma_len(sg);
113822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
1139d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
1140d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1141d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
114222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
1143d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (ata_sg_is_last(sg, qc))
1144d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
114522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
1146d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		mv_sg++;
1147d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		n_sg++;
114831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
1149d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
1150d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	return n_sg;
115131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
115231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1153e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lordstatic inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
115431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1155559eedad7f7764dacca33980127b4615011230e4Mark Lord	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
115631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		(last ? CRQB_CMD_LAST : 0);
1157559eedad7f7764dacca33980127b4615011230e4Mark Lord	*cmdw = cpu_to_le16(tmp);
115831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
115931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
116005b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
116105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_prep - Host specific command preparation.
116205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to prepare
116305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
116405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
116505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it handles prep of the CRQB
116605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      (command request block), does some sanity checking, and calls
116705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the SG load routine.
116805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
116905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
117005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
117105b308e1df6d9d673daedb517969241f41278b52Brett Russ */
117231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc)
117331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
117431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_port *ap = qc->ap;
117531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = ap->private_data;
1176e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16 *cw;
117731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_taskfile *tf;
117831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u16 flags = 0;
1179a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
118031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1181c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik 	if (qc->tf.protocol != ATA_PROT_DMA)
118231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
118320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
118431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Fill in command request block
118531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
1186e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
118731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		flags |= CRQB_FLAG_READ;
1188beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
118931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	flags |= qc->tag << CRQB_TAG_SHIFT;
11904537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* 50xx appears to ignore this*/
119131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1192bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1193bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1194a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1195a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr =
119631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1197a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr_hi =
119831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1199a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
120031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1201a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	cw = &pp->crqb[in_index].ata_cmd[0];
120231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	tf = &qc->tf;
120331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
120431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Sadly, the CRQB cannot accomodate all registers--there are
120531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * only 11 bytes...so we must pick and choose required
120631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * registers based on the command.  So, we drop feature and
120731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * hob_feature for [RW] DMA commands, but they are needed for
120831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * NCQ.  NCQ will drop hob_nsect.
120920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
121031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	switch (tf->command) {
121131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ:
121231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ_EXT:
121331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE:
121431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE_EXT:
1215c15d85c8f3f73b5f20aae7928e25b6996f16b328Jens Axboe	case ATA_CMD_WRITE_FUA_EXT:
121631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
121731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
121831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
121931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_READ:
122031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_WRITE:
12218b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
122231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
122331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
122431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif				/* FIXME: remove this line when NCQ added */
122531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	default:
122631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* The only other commands EDMA supports in non-queued and
122731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
122831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * of which are defined/used by Linux.  If we get here, this
122931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * driver needs work.
123031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 *
123131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * FIXME: modify libata to give qc_prep a return value and
123231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * return error here.
123331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
123431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		BUG_ON(tf->command);
123531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
123631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
123731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
123831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
123931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
124031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
124131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
124231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
124331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
124431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
124531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
124631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1247e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1248e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1249e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	mv_fill_sg(qc);
1250e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1251e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1252e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik/**
1253e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      mv_qc_prep_iie - Host specific command preparation.
1254e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      @qc: queued command to prepare
1255e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1256e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      This routine simply redirects to the general purpose routine
1257e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      if command is not DMA.  Else, it handles prep of the CRQB
1258e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      (command request block), does some sanity checking, and calls
1259e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      the SG load routine.
1260e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1261e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      LOCKING:
1262e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      Inherited from caller.
1263e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik */
1264e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1265e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1266e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_port *ap = qc->ap;
1267e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_port_priv *pp = ap->private_data;
1268e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_crqb_iie *crqb;
1269e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_taskfile *tf;
1270a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
1271e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 flags = 0;
1272e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1273c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik 	if (qc->tf.protocol != ATA_PROT_DMA)
1274e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1275e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1276e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* Fill in Gen IIE command request block
1277e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	 */
1278e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1279e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		flags |= CRQB_FLAG_READ;
1280e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1281beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1282e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	flags |= qc->tag << CRQB_TAG_SHIFT;
1283bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* "I/O Id" is -really-
12844537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik						   what we use as our tag */
1285e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1286bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1287bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1288a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1289a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1290e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1291e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1292e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->flags = cpu_to_le32(flags);
1293e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1294e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	tf = &qc->tf;
1295e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[0] = cpu_to_le32(
1296e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->command << 16) |
1297e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->feature << 24)
1298e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1299e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[1] = cpu_to_le32(
1300e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbal << 0) |
1301e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbam << 8) |
1302e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbah << 16) |
1303e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->device << 24)
1304e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1305e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[2] = cpu_to_le32(
1306e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbal << 0) |
1307e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbam << 8) |
1308e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbah << 16) |
1309e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_feature << 24)
1310e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1311e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[3] = cpu_to_le32(
1312e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->nsect << 0) |
1313e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_nsect << 8)
1314e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1315e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1316e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
131731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
131831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_fill_sg(qc);
131931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
132031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
132105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
132205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_issue - Initiate a command to the host
132305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to start
132405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
132505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
132605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it sanity checks our local
132705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      caches of the request producer/consumer indices then enables
132805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      DMA and bumps the request producer index.
132905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
133005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
133105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
133205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
13339a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
133431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1335c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct ata_port *ap = qc->ap;
1336c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1337c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1338c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1339bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 in_index;
134031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1341c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (qc->tf.protocol != ATA_PROT_DMA) {
134231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* We're about to send a non-EDMA capable command to the
134331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * port.  Turn off EDMA so there won't be problems accessing
134431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * shadow block, etc registers.
134531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
13460ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		__mv_stop_dma(ap);
134731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return ata_qc_issue_prot(qc);
134831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
134931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1350bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_start_dma(port_mmio, hpriv, pp);
1351bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1352bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
135331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
135431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* until we do queuing, the queue should be empty at this point */
1355a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1356a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
135731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1358bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	pp->req_idx++;
135931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1360bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
136131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
136231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and write the request in pointer to kick the EDMA to life */
1363bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
1364bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
136531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
136631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
136731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
136831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
136905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
137005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_err_intr - Handle error interrupts on the port
137105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
13729b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord *      @reset_allowed: bool: 0 == don't trigger from reset here
137305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
137405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      In most cases, just clear the interrupt and move on.  However,
137505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      some cases require an eDMA reset, which is done right before
137605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the COMRESET in mv_phy_reset().  The SERR case requires a
137705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      clear of pending errors in the SATA SERROR register.  Finally,
137805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if the port disabled DMA, update our cached copy to match.
137905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
138005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
138105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
138205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1383bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
138431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
138531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
1386bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 edma_err_cause, eh_freeze_mask, serr = 0;
1387bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1388bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1389bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
1390bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int action = 0, err_mask = 0;
1391bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_info *ehi = &ap->eh_info;
139220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1393bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_clear_desc(ehi);
139420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1395bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!edma_enabled) {
1396bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* just a guess: do we need to do this? should we
1397bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * expand this, and do it in all cases?
1398bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
139981952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_read(ap, SCR_ERROR, &serr);
140081952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_write_flush(ap, SCR_ERROR, serr);
140120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1402bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1403bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1404bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1405bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
1406bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1407bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/*
1408bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * all generations share these EDMA error cause bits
1409bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
1410bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1411bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & EDMA_ERR_DEV)
1412bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_DEV;
1413bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
14146c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
1415bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			EDMA_ERR_INTRL_PAR)) {
1416bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_ATA_BUS;
1417bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1418b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo		ata_ehi_push_desc(ehi, "parity error");
1419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1420bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
1421bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_hotplugged(ehi);
1422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
1423b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			"dev disconnect" : "dev connect");
1424bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1425bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1426ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv)) {
1427bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE_5;
1428bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1429bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
1430bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1431bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1432b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1433bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1434bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	} else {
1435bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE;
1436bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1437bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
1438bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1439bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1440b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1441bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1442bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1443bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SERR) {
1444bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			sata_scr_read(ap, SCR_ERROR, &serr);
1445bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			sata_scr_write_flush(ap, SCR_ERROR, serr);
1446bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_ATA_BUS;
1447bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			action |= ATA_EH_HARDRESET;
1448bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1449afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
145020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
145120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Clear EDMA now that SERR cleanup done */
145220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
145320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1454bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!err_mask) {
1455bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask = AC_ERR_OTHER;
1456bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1457bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1458bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1459bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->serror |= serr;
1460bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->action |= action;
1461bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1462bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc)
1463bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		qc->err_mask |= err_mask;
1464bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1465bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehi->err_mask |= err_mask;
1466bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1467bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & eh_freeze_mask)
1468bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_freeze(ap);
1469bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1470bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_abort(ap);
1471bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1472bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_pio(struct ata_port *ap)
1474bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1475bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1476bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u8 ata_status;
1477bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1478bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* ignore spurious intr if drive still BUSY */
1479bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_status = readb(ap->ioaddr.status_addr);
1480bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(ata_status & ATA_BUSY))
1481bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1482bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1483bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get active ATA command */
1484bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	qc = ata_qc_from_tag(ap, ap->active_tag);
1485bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(!qc))			/* no active tag */
1486bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1487bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc->tf.flags & ATA_TFLAG_POLLING)	/* polling; we don't own qc */
1488bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1489bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1490bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* and finally, complete the ATA command */
1491bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	qc->err_mask |= ac_err_mask(ata_status);
1492bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_qc_complete(qc);
1493bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1494bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1495bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_edma(struct ata_port *ap)
1496bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1497bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1498bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1499bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 out_index, in_index;
1502bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	bool work_done = false;
1503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get h/w response queue pointer */
1505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1506bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	while (1) {
1509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		u16 status;
15106c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		unsigned int tag;
1511bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1512bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* get s/w response queue last-read pointer, and compare */
1513bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
1514bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (in_index == out_index)
1515bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
1516bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1517bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* 50xx: get active ATA command */
15180ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		if (IS_GEN_I(hpriv))
15196c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = ap->active_tag;
1520bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15216c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		/* Gen II/IIE: get active ATA command via tag, to enable
15226c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * support for queueing.  this works transparently for
15236c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * queued and non-queued modes.
1524bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
15256c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else if (IS_GEN_II(hpriv))
15266c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15276c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_6) & 0x3f;
1528bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15296c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else /* IS_GEN_IIE */
15306c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15316c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_7) & 0x3f;
1532bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15336c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		qc = ata_qc_from_tag(ap, tag);
1534bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1535bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
1536bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * bits (WARNING: might not necessarily be associated
1537bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * with this command), which -should- be clear
1538bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * if all is well
1539bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1540bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		status = le16_to_cpu(pp->crpb[out_index].flags);
1541bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(status & 0xff)) {
1542bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1543bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			return;
1544bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1545bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1546bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* and finally, complete the ATA command */
1547bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (qc) {
1548bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			qc->err_mask |=
1549bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
1550bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_qc_complete(qc);
1551bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1552bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15530ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		/* advance software response queue pointer, to
1554bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * indicate (after the loop completes) to hardware
1555bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * that we have consumed a response queue entry.
1556bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1557bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		work_done = true;
1558bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->resp_idx++;
1559bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1560bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1561bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (work_done)
1562bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
1563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 (out_index << EDMA_RSP_Q_PTR_SHIFT),
1564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
156520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
156620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
156705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
156805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_host_intr - Handle all interrupts on the given host controller
1569cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      @host: host specific structure
157005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @relevant: port error bits relevant to this host controller
157105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @hc: which host controller we're to look at
157205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
157305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read then write clear the HC interrupt status then walk each
157405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port connected to the HC and see if it needs servicing.  Port
157505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      success ints are reported in the HC interrupt status reg, the
157605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port error ints are reported in the higher level main
157705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt status register and thus are passed in via the
157805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      'relevant' argument.
157905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
158005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
158105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
158205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1583cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
158420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
15850d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
158620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
158720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 hc_irq_cause;
1588c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int port, port0;
158920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1590351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (hc == 0)
159120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = 0;
1592351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	else
159320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = MV_PORTS_PER_HC;
159420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
159520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* we'll need the HC success int register in most cases */
159620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
1597bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!hc_irq_cause)
1598bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1599bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1600bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
160120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
160220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
160320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		hc,relevant,hc_irq_cause);
160420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
160520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
1606cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		struct ata_port *ap = host->ports[port];
160763af2a5c5990d95f1e7d8795f1425fb976ea2b4bMark Lord		struct mv_port_priv *pp = ap->private_data;
1608bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		int have_err_bits, hard_port, shift;
160955d8ca4f8094246da6e71889a4e04bfafaa78b10Jeff Garzik
1610bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
1611a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik			continue;
1612a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik
161331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		shift = port << 1;		/* (port * 2) */
161420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (port >= MV_PORTS_PER_HC) {
161520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ			shift++;	/* skip bit 8 in the HC Main IRQ reg */
161620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
1617bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		have_err_bits = ((PORT0_ERR << shift) & relevant);
1618bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1619bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(have_err_bits)) {
1620bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct ata_queued_cmd *qc;
16218b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
162220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ			qc = ata_qc_from_tag(ap, ap->active_tag);
1623bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
1624bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				continue;
1625bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1626bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1627bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			continue;
1628bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1629bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1630bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1631bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1632bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1633bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
1634bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_edma(ap);
1635bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		} else {
1636bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((DEV_IRQ << hard_port) & hc_irq_cause)
1637bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_pio(ap);
163820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
163920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
164020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("EXIT\n");
164120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
164220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1643bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_pci_error(struct ata_host *host, void __iomem *mmio)
1644bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1645bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_port *ap;
1646bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1647bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_info *ehi;
1648bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int i, err_mask, printed = 0;
1649bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 err_cause;
1650bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1651bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS);
1652bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1653bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
1654bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		   err_cause);
1655bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1656bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	DPRINTK("All regs @ PCI error\n");
1657bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1658bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1659bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
1660bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1661bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	for (i = 0; i < host->n_ports; i++) {
1662bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ap = host->ports[i];
1663bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (!ata_port_offline(ap)) {
1664bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ehi = &ap->eh_info;
1665bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_ehi_clear_desc(ehi);
1666bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (!printed++)
1667bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ata_ehi_push_desc(ehi,
1668bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik					"PCI err cause 0x%08x", err_cause);
1669bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_HOST_BUS;
1670bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ehi->action = ATA_EH_HARDRESET;
1671bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			qc = ata_qc_from_tag(ap, ap->active_tag);
1672bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc)
1673bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				qc->err_mask |= err_mask;
1674bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			else
1675bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ehi->err_mask |= err_mask;
1676bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1677bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_port_freeze(ap);
1678bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1679bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1680bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1681bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
168205b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
1683c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik *      mv_interrupt - Main interrupt event handler
168405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @irq: unused
168505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @dev_instance: private data; in this case the host structure
168605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
168705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read the read only register to determine if any host
168805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      controllers have pending interrupts.  If so, call lower level
168905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      routine to handle.  Also check for PCI errors which are only
169005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      reported here.
169105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
16928b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik *      LOCKING:
1693cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine holds the host lock while processing pending
169405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts.
169505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
16967d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mv_interrupt(int irq, void *dev_instance)
169720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
1698cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
169920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int hc, handled = 0, n_hcs;
17000d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
170120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 irq_stat;
170220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
170320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
170420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
170520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* check the cases where we either have nothing pending or have read
170620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 * a bogus register value which can indicate HW removal or PCI fault
170720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
1708351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (!irq_stat || (0xffffffffU == irq_stat))
170920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return IRQ_NONE;
171020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1711cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	n_hcs = mv_get_hc_count(host->ports[0]->flags);
1712cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_lock(&host->lock);
171320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1714bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(irq_stat & PCI_ERR)) {
1715bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_pci_error(host, mmio);
1716bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		handled = 1;
1717bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		goto out_unlock;	/* skip all other HC irq handling */
1718bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1719bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
172020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hcs; hc++) {
172120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
172220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (relevant) {
1723cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik			mv_host_intr(host, relevant, hc);
1724bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			handled = 1;
172520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
172620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1727615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
1728bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikout_unlock:
1729cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
173020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
173120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return IRQ_RETVAL(handled);
173220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
173320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1734c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1735c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1736c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1737c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1738c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1739c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return hc_mmio + ofs;
1740c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1741c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1742c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1743c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1744c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs;
1745c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1746c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	switch (sc_reg_in) {
1747c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_STATUS:
1748c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_ERROR:
1749c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_CONTROL:
1750c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = sc_reg_in * sizeof(u32);
1751c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1752c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	default:
1753c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = 0xffffffffU;
1754c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1755c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1756c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return ofs;
1757c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1758c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1759da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
1760c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
17610d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
17620d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1763c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1764c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1765da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1766da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(addr + ofs);
1767da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1768da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1769da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1770c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1771c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1772da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1773c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
17740d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
17750d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1776c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1777c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1778da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
17790d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writelfl(val, addr + ofs);
1780da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1781da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1782da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1783c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1784c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1785522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1786522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1787522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	int early_5080;
1788522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
178944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
1790522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1791522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	if (!early_5080) {
1792522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1793522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		tmp |= (1 << 0);
1794522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1795522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	}
1796522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1797522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	mv_reset_pci_bus(pdev, mmio);
1798522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1799522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1800522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1801522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1802522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1803522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1804522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
180547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1806ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
1807ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1808c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1809c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1810c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1811c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1812c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1813c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1814c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1815ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1816ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
181747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1818ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1819522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	u32 tmp;
1820522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1821522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0, mmio + MV_GPIO_PORT_CTL);
1822522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1823522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1824522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1825522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1826522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp |= ~(1 << 0);
1827522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1828ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1829ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
18302a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
18312a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
1832bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
1833c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1834c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1835c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1836c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1837c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1838c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	if (fix_apm_sq) {
1839c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_LT_MODE);
1840c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= (1 << 19);
1841c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_LT_MODE);
1842c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1843c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_PHY_CTL);
1844c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp &= ~0x3;
1845c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= 0x1;
1846c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_PHY_CTL);
1847c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1848c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1849c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1850c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= ~mask;
1851c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].pre;
1852c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].amps;
1853c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, phy_mmio + MV5_PHY_MODE);
1854bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
1855bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
1856c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1857c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1858c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, port_mmio + (reg))
1859c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1860c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port)
1861c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1862c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
1863c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1864c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1865c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1866c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	mv_channel_reset(hpriv, mmio, port);
1867c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1868c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x028);	/* command */
1869c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1870c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x004);	/* timer */
1871c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x008);	/* irq err cause */
1872c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);	/* irq err mask */
1873c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);	/* rq bah */
1874c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);	/* rq inp */
1875c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);	/* rq outp */
1876c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x01c);	/* respq bah */
1877c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x024);	/* respq outp */
1878c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x020);	/* respq inp */
1879c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x02c);	/* test control */
1880c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1881c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1882c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1883c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1884c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, hc_mmio + (reg))
1885c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1886c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int hc)
188747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik{
1888c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1889c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1890c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1891c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);
1892c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);
1893c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);
1894c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);
1895c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1896c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(hc_mmio + 0x20);
1897c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= 0x1c1c1c1c;
1898c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= 0x03030303;
1899c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, hc_mmio + 0x20);
1900c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1901c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1902c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1903c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1904c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1905c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1906c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int hc, port;
1907c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1908c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	for (hc = 0; hc < n_hc; hc++) {
1909c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		for (port = 0; port < MV_PORTS_PER_HC; port++)
1910c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			mv5_reset_hc_port(hpriv, mmio,
1911c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik					  (hc * MV_PORTS_PER_HC) + port);
1912c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1913c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mv5_reset_one_hc(hpriv, mmio, hc);
1914c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1915c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1916c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return 0;
191747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik}
191847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
1919101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1920101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#define ZERO(reg) writel(0, mmio + (reg))
1921101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1922101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1923101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1924101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1925101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_PCI_MODE);
1926101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0xff00ffff;
1927101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_PCI_MODE);
1928101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1929101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_DISC_TIMER);
1930101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_MSI_TRIGGER);
1931101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1932101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(HC_MAIN_IRQ_MASK_OFS);
1933101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_SERR_MASK);
1934101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(PCI_IRQ_CAUSE_OFS);
1935101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(PCI_IRQ_MASK_OFS);
1936101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_LOW_ADDRESS);
1937101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1938101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_ATTRIBUTE);
1939101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_COMMAND);
1940101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1941101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1942101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1943101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1944101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1945101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1946101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1947101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	mv5_reset_flash(hpriv, mmio);
1948101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1949101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_GPIO_PORT_CTL);
1950101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0x3;
1951101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp |= (1 << 5) | (1 << 6);
1952101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_GPIO_PORT_CTL);
1953101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1954101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1955101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik/**
1956101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      mv6_reset_hc - Perform the 6xxx global soft reset
1957101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      @mmio: base address of the HBA
1958101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1959101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      This routine only applies to 6xxx parts.
1960101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1961101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      LOCKING:
1962101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      Inherited from caller.
1963101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik */
1964c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1965c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1966101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1967101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1968101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	int i, rc = 0;
1969101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 t;
1970101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1971101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* Following procedure defined in PCI "main command and status
1972101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 * register" table.
1973101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 */
1974101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	t = readl(reg);
1975101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(t | STOP_PCI_MASTER, reg);
1976101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1977101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	for (i = 0; i < 1000; i++) {
1978101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
1979101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
1980101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		if (PCI_MASTER_EMPTY & t) {
1981101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik			break;
1982101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		}
1983101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
1984101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(PCI_MASTER_EMPTY & t)) {
1985101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
1986101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
1987101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
1988101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
1989101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1990101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* set reset */
1991101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
1992101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
1993101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t | GLOB_SFT_RST, reg);
1994101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
1995101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
1996101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
1997101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1998101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(GLOB_SFT_RST & t)) {
1999101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
2000101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2001101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2002101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2003101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2004101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
2005101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2006101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2007101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
2008101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2009101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2010101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while ((GLOB_SFT_RST & t) && (i-- > 0));
2011101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2012101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (GLOB_SFT_RST & t) {
2013101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
2014101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2015101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2016101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikdone:
2017101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	return rc;
2018101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2019101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
202047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
2021ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
2022ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
2023ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	void __iomem *port_mmio;
2024ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	u32 tmp;
2025ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2026ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(mmio + MV_RESET_CFG);
2027ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	if ((tmp & (1 << 0)) == 0) {
202847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->signal[idx].amps = 0x7 << 8;
2029ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		hpriv->signal[idx].pre = 0x1 << 5;
2030ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		return;
2031ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	}
2032ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2033ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	port_mmio = mv_port_base(mmio, idx);
2034ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(port_mmio + PHY_MODE2);
2035ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2036ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
2037ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
2038ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2039ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
204047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
2041ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
204247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
2043ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2044ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2045c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
20462a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
2047bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
2048c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
2049c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2050bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
205147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	int fix_phy_mode2 =
205247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
2053bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	int fix_phy_mode4 =
205447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
205547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	u32 m2, tmp;
205647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
205747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (fix_phy_mode2) {
205847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
205947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~(1 << 16);
206047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 |= (1 << 31);
206147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
206247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
206347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
206447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
206547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
206647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~((1 << 16) | (1 << 31));
206747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
206847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
206947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
207047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	}
207147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
207247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* who knows what this magic does */
207347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp = readl(port_mmio + PHY_MODE3);
207447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp &= ~0x7F800000;
207547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp |= 0x2A800000;
207647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(tmp, port_mmio + PHY_MODE3);
2077bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2078bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (fix_phy_mode4) {
207947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		u32 m4;
2080bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2081bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = readl(port_mmio + PHY_MODE4);
208247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
208447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			tmp = readl(port_mmio + 0x310);
2085bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2086bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = (m4 & ~(1 << 1)) | (1 << 0);
2087bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2088bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		writel(m4, port_mmio + PHY_MODE4);
208947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
209047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
209147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			writel(tmp, port_mmio + 0x310);
2092bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2093bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2094bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	/* Revert values of pre-emphasis and signal amps to the saved ones */
2095bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 = readl(port_mmio + PHY_MODE2);
2096bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2097bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 &= ~MV_M2_PREAMP_MASK;
20982a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].amps;
20992a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].pre;
210047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	m2 &= ~(1 << 16);
2101bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2102e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* according to mvSata 3.6.1, some IIE values are fixed */
2103e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (IS_GEN_IIE(hpriv)) {
2104e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 &= ~0xC30FF01F;
2105e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 |= 0x0000900F;
2106e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
2107e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2108bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	writel(m2, port_mmio + PHY_MODE2);
2109bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2110bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2111c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
2112c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no)
2113c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
2114c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port_no);
2115c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2116c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
2117c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2118ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv)) {
2119c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2120eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl |= (1 << 7);		/* enable gen2i speed */
2121eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2122c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2123c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
2124c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2125c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	udelay(25);		/* allow reset propagation */
2126c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2127c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	/* Spec never mentions clearing the bit.  Marvell's driver does
2128c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 * clear the bit, however.
2129c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 */
2130c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(0, port_mmio + EDMA_CMD_OFS);
2131c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2132c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->ops->phy_errata(hpriv, mmio, port_no);
2133c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2134ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2135c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mdelay(1);
2136c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
2137c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
213805b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
2139bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik *      mv_phy_reset - Perform eDMA reset followed by COMRESET
214005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
214105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
214205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Part of this is taken from __sata_phy_reset and modified to
214305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      not sleep since this routine gets called from interrupt level.
214405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
214505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
214605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.  This is coded to safe to call at
214705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt level, i.e. it does not sleep.
214831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ */
2149bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_phy_reset(struct ata_port *ap, unsigned int *class,
2150bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 unsigned long deadline)
215120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2152095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2153cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
215420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
215522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	int retry = 5;
215622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	u32 sstatus;
215720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
215820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
215920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2160da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2161da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2162da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2163da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2164da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2165da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2166da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2167da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
2168da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", status, serror, scontrol);
2169da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2170da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
217120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
217222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* Issue COMRESET via SControl */
217322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzikcomreset_retry:
217481952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
2175bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(1);
217622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
217781952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
2178bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(20);
217922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
218031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	do {
218181952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_read(ap, SCR_STATUS, &sstatus);
218262f1d0e6de138b91d55fbd7d579c837ed62e9e31Andres Salomon		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
218331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
218422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2185bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(1);
2186c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	} while (time_before(jiffies, deadline));
218720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
218822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* work around errata */
2189ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv) &&
219022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
219122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (retry-- > 0))
219222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		goto comreset_retry;
2193095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2194da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2195da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2196da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2197da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2198da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2199da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2200da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2201da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
2202da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2203da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2204da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
220531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2206bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ata_port_offline(ap)) {
2207bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		*class = ATA_DEV_NONE;
220820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return;
220920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
221020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
221122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* even after SStatus reflects that device is ready,
221222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * it seems to take a while for link to be fully
221322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * established (and thus Status no longer 0x80/0x7F),
221422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * so we poll a bit for that, here.
221522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 */
221622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	retry = 20;
221722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	while (1) {
221822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		u8 drv_stat = ata_check_status(ap);
221922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
222022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2221bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(500);
222222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if (retry-- <= 0)
222322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2224bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (time_after(jiffies, deadline))
2225bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
222622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	}
222722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2228bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: if we passed the deadline, the following
2229bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * code probably produces an invalid result
2230bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
223120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2232bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* finally, read device signature from TF registers */
2233bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	*class = ata_dev_try_classify(ap, 0, NULL);
2234095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2235095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2236095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2237bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
2238095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2239bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	VPRINTK("EXIT\n");
224020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
224120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2242bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic int mv_prereset(struct ata_port *ap, unsigned long deadline)
224322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik{
2244bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2245bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_context *ehc = &ap->eh_context;
2246bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	int rc;
22470ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
2248bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	rc = mv_stop_dma(ap);
2249bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (rc)
2250bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2251bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2252bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) {
2253bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
2254bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2255bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2256bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2257bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* if we're about to do hardreset, nothing more to do */
2258bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ehc->i.action & ATA_EH_HARDRESET)
2259bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return 0;
2260bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2261bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ata_port_online(ap))
2262bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = ata_wait_ready(ap, deadline);
2263bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
2264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = -ENODEV;
2265bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2266bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return rc;
226722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik}
226822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic int mv_hardreset(struct ata_port *ap, unsigned int *class,
2270bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			unsigned long deadline)
227131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
2272bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
22730d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
227431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(ap);
227631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2277bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_channel_reset(hpriv, mmio, ap->port_no);
227831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2279bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_phy_reset(ap, class, deadline);
2280bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2281bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return 0;
2282bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2283bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2284bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_postreset(struct ata_port *ap, unsigned int *classes)
2285bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2286bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 serr;
2287bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2288bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* print link status */
2289bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_print_link_status(ap);
229031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2291bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear SError */
2292bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_scr_read(ap, SCR_ERROR, &serr);
2293bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_scr_write_flush(ap, SCR_ERROR, serr);
2294bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2295bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* bail out if no device is present */
2296bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
2297bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		DPRINTK("EXIT, no device\n");
2298bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
22999b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord	}
2300bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2301bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* set up device control */
2302bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
2303bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2304bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2305bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap)
2306bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2307bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_do_eh(ap, mv_prereset, ata_std_softreset,
2308bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		  mv_hardreset, mv_postreset);
2309bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2310bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2311bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc)
2312bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2313bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(qc->ap);
2314bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2315bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2316bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap)
2317bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2318bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2319bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2320bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask;
2321bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift;
2322bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2323bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2324bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2325bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2326bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0)
2327bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2328bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2329bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2330bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2331bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* disable assertion of portN err, done events */
2332bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2333bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
2334bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2335bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2336bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap)
2337bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2338bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2339bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2340bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2341bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
2342bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask, hc_irq_cause;
2343bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift, hc_port_no = ap->port_no;
2344bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2345bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2346bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2347bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2348bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0) {
2349bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2350bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hc_port_no -= 4;
2351bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2352bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2353bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2354bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2355bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear EDMA errors on this port */
2356bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2357bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2358bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear pending irq events */
2359bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
2360bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << hc_port_no);	/* clear CRPB-done */
2361bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
2362bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
2363bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2364bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* enable assertion of portN err, done events */
2365bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2366bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
236731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
236831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
236905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
237005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_init - Perform some early initialization on a single port.
237105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port: libata data structure storing shadow register addresses
237205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port_mmio: base address of the port
237305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
237405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Initialize shadow register mmio addresses, clear outstanding
237505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts on the port, and unmask interrupts for the future
237605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      start of the port.
237705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
237805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
237905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
238005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
238131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
238220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
23830d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
238431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	unsigned serr_ofs;
238531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
23868b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* PIO related setup
238731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
238831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
23898b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->error_addr =
239031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
239131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
239231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
239331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
239431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
239531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
23968b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->status_addr =
239731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
239831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* special case: control/altstatus doesn't have ATA_REG_ address */
239931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
240031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
240131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* unused: */
24028d9db2d2fbae9e05022825c32f86e00c8e342860Randy Dunlap	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
240320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
240431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding port interrupt conditions */
240531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	serr_ofs = mv_scr_offset(SCR_ERROR);
240631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
240731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
240831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
240920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* unmask all EDMA error interrupts */
241031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
241120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24128b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
241331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_CFG_OFS),
241431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
241531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
241620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
241720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24184447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2419bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
24204447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
24214447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2422bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
2423bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2424bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	switch(board_idx) {
242547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	case chip_5080:
242647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2427ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
242847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
242944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
243047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x1:
243147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
243247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
243347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
243447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
243547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
243647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
243747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
243847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying 50XXB2 workarounds to unknown rev\n");
243947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
244047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
244147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		}
244247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		break;
244347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
2444bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_504x:
2445bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_508x:
244647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2447ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
2448bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
244944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
245047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x0:
245147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
245247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
245347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
245447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
245547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
245647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
245747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
245847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying B2 workarounds to unknown rev\n");
245947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
246047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
2461bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2462bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2463bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2464bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_604x:
2465bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_608x:
246647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv6xxx_ops;
2467ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_II;
246847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
246944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
247047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x7:
247147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
247247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
247347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x9:
247447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2475bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2476bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		default:
2477bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
247847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik				   "Applying B2 workarounds to unknown rev\n");
247947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
2480bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2481bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2482bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2483bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2484e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_7042:
2485e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_6042:
2486e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hpriv->ops = &mv6xxx_ops;
2487e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hp_flags |= MV_HP_GEN_IIE;
2488e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
248944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
2490e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x0:
2491e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_XX42A0;
2492e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2493e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x1:
2494e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2495e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2496e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		default:
2497e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
2498e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			   "Applying 60X1C0 workarounds to unknown rev\n");
2499e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2500e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2501e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		}
2502e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		break;
2503e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2504bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	default:
2505bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
2506bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		return 1;
2507bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2508bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2509bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	hpriv->hp_flags = hp_flags;
2510bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2511bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	return 0;
2512bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2513bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
251405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
251547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik *      mv_init_host - Perform some early initialization of the host.
25164447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *	@host: ATA host to initialize
25174447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @board_idx: controller index
251805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
251905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      If possible, do an early global reset of the host.  Then do
252005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      our port init and clear/unmask all/relevant host interrupts.
252105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
252205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
252305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
252405b308e1df6d9d673daedb517969241f41278b52Brett Russ */
25254447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_init_host(struct ata_host *host, unsigned int board_idx)
252620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
252720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	int rc = 0, n_hc, port, hc;
25284447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
25294447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
25304447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2531bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
253247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* global interrupt mask */
253347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
253447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
25354447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_chip_id(host, board_idx);
2536bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (rc)
2537bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		goto done;
2538bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25394447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_hc = mv_get_hc_count(host->ports[0]->flags);
2540bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25414447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++)
254247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops->read_preamp(hpriv, port, mmio);
254320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2544c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
254547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (rc)
254620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		goto done;
254720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2548522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_flash(hpriv, mmio);
2549522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_bus(pdev, mmio);
255047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	hpriv->ops->enable_leds(hpriv, mmio);
255120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
25524447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2553ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		if (IS_GEN_II(hpriv)) {
2554c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			void __iomem *port_mmio = mv_port_base(mmio, port);
2555c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
25562a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2557eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl |= (1 << 7);		/* enable gen2i speed */
2558eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
25592a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
25602a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		}
25612a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
2562c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		hpriv->ops->phy_errata(hpriv, mmio, port);
25632a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	}
25642a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
25654447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
25662a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		void __iomem *port_mmio = mv_port_base(mmio, port);
25674447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
256820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
256920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
257020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hc; hc++) {
257131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
257231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
257331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
257431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			"(before clear)=0x%08x\n", hc,
257531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_CFG_OFS),
257631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
257731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
257831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* Clear any currently outstanding hc interrupt conditions */
257931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
258020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
258120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
258231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding host interrupt conditions */
258331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
258431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
258531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and unmask interrupt generation for host regs */
258631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
2587fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik
2588ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2589fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2590fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	else
2591fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
259220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
259320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
25948b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		"PCI int cause/mask=0x%08x/0x%08x\n",
259520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
259620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
259720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + PCI_IRQ_CAUSE_OFS),
259820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + PCI_IRQ_MASK_OFS));
2599bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
260031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russdone:
260120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return rc;
260220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
260320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
260405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
260505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_print_info - Dump key info to kernel log for perusal.
26064447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @host: ATA host to print info about
260705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
260805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      FIXME: complete this.
260905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
261005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
261105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
261205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
26134447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic void mv_print_info(struct ata_host *host)
261431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
26154447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
26164447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
261744c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	u8 scc;
2618c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	const char *scc_s, *gen;
261931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
262031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Use this to determine the HW stepping of the chip so we know
262131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * what errata to workaround
262231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
262331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
262431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (scc == 0)
262531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "SCSI";
262631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else if (scc == 0x01)
262731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "RAID";
262831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else
2629c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		scc_s = "?";
2630c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik
2631c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	if (IS_GEN_I(hpriv))
2632c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "I";
2633c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_II(hpriv))
2634c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "II";
2635c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_IIE(hpriv))
2636c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "IIE";
2637c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else
2638c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "?";
263931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2640a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	dev_printk(KERN_INFO, &pdev->dev,
2641c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
2642c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
264331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
264431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
264531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
264605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
264705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_init_one - handle a positive probe of a Marvell host
264805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pdev: PCI device found
264905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ent: PCI device ID entry for the matched host
265005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
265105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
265205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
265305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
265420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
265520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
265620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	static int printed_version = 0;
265720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int board_idx = (unsigned int)ent->driver_data;
26584447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
26594447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
26604447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv;
26614447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int n_ports, rc;
266220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2663a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	if (!printed_version++)
2664a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
266520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
26664447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
26674447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
26684447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
26694447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
26704447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
26714447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host || !hpriv)
26724447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
26734447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->private_data = hpriv;
26744447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
26754447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* acquire resources */
267624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
267724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
267820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return rc;
267920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
26800d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
26810d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
268224dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
26830d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
268424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
26854447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
268620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2687d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	rc = pci_go_64(pdev);
2688d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (rc)
2689d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		return rc;
2690d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
269120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* initialize adapter */
26924447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_init_host(host, board_idx);
269324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
269424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
269520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
269631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Enable interrupts */
26976a59dcf8678cbc4106a8a6e158d7408a87691358Tejun Heo	if (msi && pci_enable_msi(pdev))
269831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pci_intx(pdev, 1);
269920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
270031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_pci_cfg(pdev, 0x68);
27014447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mv_print_info(host);
270220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27034447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	pci_set_master(pdev);
2704ea8b4db97aa41a66c05daa4055a1974692ccd52dJeff Garzik	pci_try_set_mwi(pdev);
27054447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
2706c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
270720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
270820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
270920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int __init mv_init(void)
271020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2711b7887196e38da54ff893897b80875d632d1a1114Pavel Roskin	return pci_register_driver(&mv_pci_driver);
271220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
271320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
271420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void __exit mv_exit(void)
271520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
271620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	pci_unregister_driver(&mv_pci_driver);
271720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
271820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
271920f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_AUTHOR("Brett Russ");
272020f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
272120f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_LICENSE("GPL");
272220f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DEVICE_TABLE(pci, mv_pci_tbl);
272320f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_VERSION(DRV_VERSION);
272420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2725ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikmodule_param(msi, int, 0444);
2726ddef9bb367b19383df627e388cb4c01c86ddba6cJeff GarzikMODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2727ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
272820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_init(mv_init);
272920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_exit(mv_exit);
2730