sata_mv.c revision 02a121da5a53d415b6596bc19cc6999d295d32a4
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>
726c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik#include <scsi/scsi_device.h>
7320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/libata.h>
7420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
7520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#define DRV_NAME	"sata_mv"
766c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik#define DRV_VERSION	"1.01"
7720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
7820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russenum {
7920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* BAR's are enumerated in terms of pci_resource_start() terms */
8020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */
8120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IO_BAR		= 2,	/* offset 0x18: IO space */
8220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */
8320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */
8520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */
8620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_BASE		= 0,
8820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
89615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
90615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
91615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
92615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
93615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
94615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
9520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC0_REG_BASE	= 0x20000,
96522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_FLASH_CTL		= 0x1046c,
97bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_GPIO_PORT_CTL	= 0x104f0,
98bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_RESET_CFG		= 0x180d8,
9920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
10020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,
10120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,
10220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
10320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
10420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
10531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH		= 32,
10631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
10731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
10931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * CRPB needs alignment on a 256B boundary. Size == 256B
11031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
11131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
11231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
11331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
11431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
11531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_SG_CT		= 176,
11631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
11731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
11831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORTS_PER_HC		= 4,
12020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
12120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_HC_SHIFT	= 2,
12231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
12320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_MASK		= 3,
12420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
12520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Host Flags */
12620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
12720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
128c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	MV_COMMON_FLAGS		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
129bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
130bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_PIO_POLLING,
13147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,
13220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
13331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_FLAG_READ		= (1 << 0),
13431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_TAG_SHIFT		= 1,
135c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_IOID_SHIFT		= 6,	/* CRQB Gen-II/IIE IO Id shift */
136c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_HOSTQ_SHIFT	= 17,	/* CRQB Gen-II/IIE HostQueTag shift */
13731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_ADDR_SHIFT	= 8,
13831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_CS		= (0x2 << 11),
13931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_LAST		= (1 << 15),
14031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_FLAG_STATUS_SHIFT	= 8,
142c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_6	= 5,	/* CRPB Gen-II IO Id shift */
143c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_7	= 7,	/* CRPB Gen-IIE IO Id shift */
14431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EPRD_FLAG_END_OF_TBL	= (1 << 31),
14631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* PCI interface registers */
14820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
14931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	PCI_COMMAND_OFS		= 0xc00,
15031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
15120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MAIN_CMD_STS_OFS	= 0xd30,
15220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	STOP_PCI_MASTER		= (1 << 2),
15320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MASTER_EMPTY	= (1 << 3),
15420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GLOB_SFT_RST		= (1 << 4),
15520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
156522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MODE		= 0xd00,
157522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,
158522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_DISC_TIMER	= 0xd04,
159522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MSI_TRIGGER	= 0xc38,
160522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_SERR_MASK	= 0xc28,
161522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_XBAR_TMOUT	= 0x1d04,
162522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,
163522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,
164522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,
165522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_COMMAND	= 0x1d50,
166522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
16702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCI_IRQ_CAUSE_OFS	= 0x1d58,
16802a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCI_IRQ_MASK_OFS	= 0x1d5c,
16920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
17020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
17102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCIE_IRQ_CAUSE_OFS	= 0x1900,
17202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCIE_IRQ_MASK_OFS	= 0x1910,
17302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCIE_UNMASK_ALL_IRQS	= 0x70a,	/* assorted bits */
17402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
17520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
17620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
17720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_ERR		= (1 << 0),	/* shift by port # */
17820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_DONE		= (1 << 1),	/* shift by port # */
17920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
18020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
18120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_ERR			= (1 << 18),
18220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
18320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
184fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_0_3_COAL_DONE	= (1 << 8),
185fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_4_7_COAL_DONE	= (1 << 17),
18620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
18720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GPIO_INT		= (1 << 22),
18820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SELF_INT		= (1 << 23),
18920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TWSI_INT		= (1 << 24),
19020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
191fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
1928b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
19320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
19420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   HC_MAIN_RSVD),
195fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
196fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik				   HC_MAIN_RSVD_5),
19720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
19820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATAHC registers */
19920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_CFG_OFS		= 0,
20020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_CAUSE_OFS	= 0x14,
20231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
20320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
20420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	DEV_IRQ			= (1 << 8),	/* shift by port # */
20520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Shadow block registers */
20731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_BLK_OFS		= 0x100,
20831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
20920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATA registers */
21120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
21220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_ACTIVE_OFS		= 0x350,
21347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	PHY_MODE3		= 0x310,
214bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE4		= 0x314,
215bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE2		= 0x330,
216c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_MODE		= 0x74,
217c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_LT_MODE		= 0x30,
218c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_CTL		= 0x0C,
219bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	SATA_INTERFACE_CTL	= 0x050,
220bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
221bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_M2_PREAMP_MASK	= 0x7e0,
22220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
22320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Port registers */
22420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_CFG_OFS		= 0,
22531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
22631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ		= (1 << 5),
22731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
22831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
22931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
23020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
23120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
23220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
2336c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
2346c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
2356c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV		= (1 << 2),	/* device error */
2366c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
2376c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
2386c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
239c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
240c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
2416c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
242c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
2436c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
2446c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
2456c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
2466c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
2476c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
24820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
2496c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
2506c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
2516c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
2526c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
253c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_OVERRUN_5	= (1 << 5),
254c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_UNDERRUN_5	= (1 << 6),
255bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
256bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
257bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
258bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
259bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SERR |
260bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS |
2616c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
262bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
263bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY |
265bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_CTRL_RX_2 |
266bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_RX |
267bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_TX |
268bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_TRANS_PROTO,
269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE_5	= EDMA_ERR_D_PAR |
270bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
271bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
272bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
273bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_OVERRUN_5 |
274bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_UNDERRUN_5 |
275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS_5 |
2766c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
277bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
278bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
279bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY,
28020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
28131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
28231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
28331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
28431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
28531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_PTR_SHIFT	= 5,
28631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
28731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
28831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
28931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
29031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_PTR_SHIFT	= 3,
29131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2920ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
2930ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_EN			= (1 << 0),	/* enable EDMA */
2940ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
2950ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
29620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
297c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	EDMA_IORDY_TMOUT	= 0x34,
298bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	EDMA_ARB_CFG		= 0x38,
299bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
30031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Host private flags (hp_flags) */
30131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_HP_FLAG_MSI		= (1 << 0),
30247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB0	= (1 << 1),
30347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB2	= (1 << 2),
30447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1B2	= (1 << 3),
30547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1C0	= (1 << 4),
306e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	MV_HP_ERRATA_XX42A0	= (1 << 5),
3070ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
3080ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
3090ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
31002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	MV_HP_PCIE		= (1 << 9),	/* PCIe bus/regs: 7042 */
31120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
31231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Port private flags (pp_flags) */
3130ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
3140ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
31520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
31620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
317ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
318ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
319e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
320bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
321095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzikenum {
322baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	/* DMA boundary 0xffff is required by the s/g splitting
323baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 * we need on /length/ in mv_fill-sg().
324baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 */
325baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	MV_DMA_BOUNDARY		= 0xffffU,
326095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3270ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* mask of register bits containing lower 32 bits
3280ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 * of EDMA request queue DMA address
3290ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 */
330095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
331095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3320ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* ditto, for response queue */
333095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
334095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik};
335095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
336522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikenum chip_type {
337522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_504x,
338522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_508x,
339522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_5080,
340522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_604x,
341522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_608x,
342e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_6042,
343e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_7042,
344522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik};
345522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
34631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ReQuest Block: 32B */
34731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crqb {
348e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr;
349e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr_hi;
350e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ctrl_flags;
351e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ata_cmd[11];
35231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
35320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
354e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstruct mv_crqb_iie {
355e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
356e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
357e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags;
358e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			len;
359e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			ata_cmd[4];
360e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
361e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
36231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ResPonse Block: 8B */
36331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crpb {
364e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			id;
365e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			flags;
366e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			tmstmp;
36720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
36820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
36931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
37031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_sg {
371e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
372e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags_size;
373e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
374e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			reserved;
37531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
37620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
37731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_port_priv {
37831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crqb		*crqb;
37931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crqb_dma;
38031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crpb		*crpb;
38131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crpb_dma;
38231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_sg		*sg_tbl;
38331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		sg_tbl_dma;
384bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
385bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		req_idx;
386bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		resp_idx;
387bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
38831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			pp_flags;
38931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
39031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
391bca1c4eb9411533d613123618c0d127fae532595Jeff Garzikstruct mv_port_signal {
392bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			amps;
393bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			pre;
394bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik};
395bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
39602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lordstruct mv_host_priv {
39702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			hp_flags;
39802a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_port_signal	signal[8];
39902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	const struct mv_hw_ops	*ops;
40002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			irq_cause_ofs;
40102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			irq_mask_ofs;
40202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			unmask_all_irqs;
40302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord};
40402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
40547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_hw_ops {
4062a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
4072a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
40847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
40947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
41047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
411c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
412c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
413522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
414522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
41547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
41647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
41720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void mv_irq_clear(struct ata_port *ap);
418da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
419da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
420da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
421da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
42231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap);
42331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap);
42431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc);
425e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc);
4269a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
427bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap);
428bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc);
429bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap);
430bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap);
43120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
43220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
4332a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4342a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
43547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
43647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
43747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
438c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
439c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
440522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
441522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
44247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
4432a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4442a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
44547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
44647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
44747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
448c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
449c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
450522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
451522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
452c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
453c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no);
45447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
455c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv5_sht = {
456c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.module			= THIS_MODULE,
457c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.name			= DRV_NAME,
458c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.ioctl			= ata_scsi_ioctl,
459c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.queuecommand		= ata_scsi_queuecmd,
460c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
461c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.this_id		= ATA_SHT_THIS_ID,
462baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
463c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
464c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.emulated		= ATA_SHT_EMULATED,
465c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.use_clustering		= 1,
466c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.proc_name		= DRV_NAME,
467c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.dma_boundary		= MV_DMA_BOUNDARY,
4683be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	.slave_configure	= ata_scsi_slave_config,
469c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.slave_destroy		= ata_scsi_slave_destroy,
470c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.bios_param		= ata_std_bios_param,
471c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik};
472c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
473c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv6_sht = {
47420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.module			= THIS_MODULE,
47520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
47620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.ioctl			= ata_scsi_ioctl,
47720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.queuecommand		= ata_scsi_queuecmd,
478c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
47920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.this_id		= ATA_SHT_THIS_ID,
480baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
48120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
48220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.emulated		= ATA_SHT_EMULATED,
483d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	.use_clustering		= 1,
48420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.proc_name		= DRV_NAME,
48520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dma_boundary		= MV_DMA_BOUNDARY,
4863be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	.slave_configure	= ata_scsi_slave_config,
487ccf68c3405fca11386004674377d951b9b18e756Tejun Heo	.slave_destroy		= ata_scsi_slave_destroy,
48820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.bios_param		= ata_std_bios_param,
48920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
49020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
491c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv5_ops = {
492c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_load		= ata_tf_load,
493c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_read		= ata_tf_read,
494c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.check_status		= ata_check_status,
495c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.exec_command		= ata_exec_command,
496c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.dev_select		= ata_std_dev_select,
497c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
498cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
499c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
500c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_prep		= mv_qc_prep,
501c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_issue		= mv_qc_issue,
5020d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
503c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
504c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.irq_clear		= mv_irq_clear,
505246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
506c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
510bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
511bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
512c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_read		= mv5_scr_read,
513c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_write		= mv5_scr_write,
514c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
515c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_start		= mv_port_start,
516c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_stop		= mv_port_stop,
517c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik};
518c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
519c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv6_ops = {
52020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_load		= ata_tf_load,
52120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_read		= ata_tf_read,
52220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.check_status		= ata_check_status,
52320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.exec_command		= ata_exec_command,
52420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dev_select		= ata_std_dev_select,
52520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
526cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
52720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
52831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_prep		= mv_qc_prep,
52931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_issue		= mv_qc_issue,
5300d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
53120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
53220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.irq_clear		= mv_irq_clear,
533246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
53420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
535bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
536bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
537bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
538bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
539bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
54020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_read		= mv_scr_read,
54120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_write		= mv_scr_write,
54220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
54331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_start		= mv_port_start,
54431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_stop		= mv_port_stop,
54520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
54620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
547e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic const struct ata_port_operations mv_iie_ops = {
548e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_load		= ata_tf_load,
549e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_read		= ata_tf_read,
550e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.check_status		= ata_check_status,
551e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.exec_command		= ata_exec_command,
552e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.dev_select		= ata_std_dev_select,
553e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
554cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
555e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
556e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_prep		= mv_qc_prep_iie,
557e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_issue		= mv_qc_issue,
5580d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
559e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
560e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.irq_clear		= mv_irq_clear,
561246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
562e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
565bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
566bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
567bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
568e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_read		= mv_scr_read,
569e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_write		= mv_scr_write,
570e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
571e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_start		= mv_port_start,
572e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_stop		= mv_port_stop,
573e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
574e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
57598ac62defe529d04a192688f40d801a2d8fbcf98Arjan van de Venstatic const struct ata_port_info mv_port_info[] = {
57620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_504x */
577cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= MV_COMMON_FLAGS,
57831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
579bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
580c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
58120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
58220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_508x */
583c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
58431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
585bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
586c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
58720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
58847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	{  /* chip_5080 */
589c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
59047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
591bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
592c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
59347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	},
59420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_604x */
595c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
59631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
597bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
598c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
59920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
60020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_608x */
601c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
602c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				  MV_FLAG_DUAL_HC,
60331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
604bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
605c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
60620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
607e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_6042 */
608c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
609e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
610bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
611e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
612e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
613e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_7042 */
614c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
615e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
616bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
617e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
618e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
61920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
62020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
6213b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id mv_pci_tbl[] = {
6222d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
6232d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
6242d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
6252d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
626cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	/* RocketRAID 1740/174x have different identifiers */
627cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
628cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
6292d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6302d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
6312d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
6322d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
6332d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
6342d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
6352d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6362d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
6372d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
638d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	/* Adaptec 1430SA */
639d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
640d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger
64102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	/* Marvell 7042 support */
6426a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
6436a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom
64402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	/* Highpoint RocketRAID PCIe series */
64502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	{ PCI_VDEVICE(TTI, 0x2300), chip_7042 },
64602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
64702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
6482d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ }			/* terminate list */
64920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
65020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
65120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic struct pci_driver mv_pci_driver = {
65220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
65320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.id_table		= mv_pci_tbl,
65420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.probe			= mv_init_one,
65520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.remove			= ata_pci_remove_one,
65620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
65720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
65847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv5xxx_ops = {
65947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv5_phy_errata,
66047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv5_enable_leds,
66147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv5_read_preamp,
66247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv5_reset_hc,
663522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv5_reset_flash,
664522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv5_reset_bus,
66547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
66647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
66747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv6xxx_ops = {
66847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv6_phy_errata,
66947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv6_enable_leds,
67047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv6_read_preamp,
67147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv6_reset_hc,
672522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv6_reset_flash,
673522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv_reset_pci_bus,
67447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
67547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
67620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ/*
677ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik * module options
678ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik */
679ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikstatic int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
680ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
681ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
682d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik/* move to PCI layer or libata core? */
683d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzikstatic int pci_go_64(struct pci_dev *pdev)
684d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik{
685d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	int rc;
686d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
687d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
688d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
689d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
690d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
691d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			if (rc) {
692d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				dev_printk(KERN_ERR, &pdev->dev,
693d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik					   "64-bit DMA enable failed\n");
694d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				return rc;
695d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			}
696d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
697d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	} else {
698d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
699d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
700d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
701d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit DMA enable failed\n");
702d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
703d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
704d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
705d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
706d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
707d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit consistent DMA enable failed\n");
708d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
709d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
710d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	}
711d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
712d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	return rc;
713d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik}
714d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
715ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik/*
71620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Functions
71720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ */
71820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
71920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void writelfl(unsigned long data, void __iomem *addr)
72020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writel(data, addr);
72220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	(void) readl(addr);	/* flush to avoid PCI posted write */
72320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
72420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
72520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
72620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
72820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
72920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
730c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hc_from_port(unsigned int port)
731c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
732c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port >> MV_PORT_HC_SHIFT;
733c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
734c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
735c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hardport_from_port(unsigned int port)
736c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
737c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port & MV_PORT_MASK;
738c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
739c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
740c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline void __iomem *mv_hc_base_from_port(void __iomem *base,
741c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik						 unsigned int port)
742c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
743c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return mv_hc_base(base, mv_hc_from_port(port));
744c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
745c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
74620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
74720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
748c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return  mv_hc_base_from_port(base, port) +
7498b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		MV_SATAHC_ARBTR_REG_SZ +
750c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
75120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
75320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_ap_base(struct ata_port *ap)
75420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
7550d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
75620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
758cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic inline int mv_get_hc_count(unsigned long port_flags)
75931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
760cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
76131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
76231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
76331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_irq_clear(struct ata_port *ap)
76420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
76520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
76620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
767c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_set_edma_ptrs(void __iomem *port_mmio,
768c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_host_priv *hpriv,
769c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_port_priv *pp)
770c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik{
771bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 index;
772bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
773c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
774c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize request queue
775c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
776bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
777bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
778c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crqb_dma & 0x3ff);
779c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
780bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
781c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
782c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
783c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
784bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crqb_dma & 0xffffffff) | index,
785c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
786c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
787bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
788c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
789c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
790c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize response queue
791c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
792bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
793bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
794c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crpb_dma & 0xff);
795c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
796c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
797c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
798bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & 0xffffffff) | index,
799c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
800c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
801bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
802c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
803bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
804c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
805c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik}
806c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
80705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
80805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_start_dma - Enable eDMA engine
80905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @base: port base address
81005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pp: port private data
81105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
812beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
813beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
81405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
81505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
81605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
81705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
818c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
819c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 struct mv_port_priv *pp)
82020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
821c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
822bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* clear EDMA event indicators, if any */
823bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
824bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
825bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_set_edma_ptrs(base, hpriv, pp);
826bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
827afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
828afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
829afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
830beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
83120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
83220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
83305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
8340ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik *      __mv_stop_dma - Disable eDMA engine
83505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
83605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
837beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
838beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
83905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
84005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
84105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
84205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
8430ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int __mv_stop_dma(struct ata_port *ap)
84420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
84531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
84631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp	= ap->private_data;
84731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 reg;
848c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int i, err = 0;
84931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
8504537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
851afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		/* Disable EDMA if active.   The disable bit auto clears.
85231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
85331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
85431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
855afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	} else {
856beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
8572dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	}
8588b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
85931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* now properly wait for the eDMA to stop */
86031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (i = 1000; i > 0; i--) {
86131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		reg = readl(port_mmio + EDMA_CMD_OFS);
8624537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		if (!(reg & EDMA_EN))
86331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
8644537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik
86531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		udelay(100);
86631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
86731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
868c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (reg & EDMA_EN) {
869f15a1dafed22d5037e0feea7528e1eeb28a1a7a3Tejun Heo		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
870c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		err = -EIO;
87131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
872c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
873c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	return err;
87420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
87520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8760ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int mv_stop_dma(struct ata_port *ap)
8770ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik{
8780ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
8790ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	int rc;
8800ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8810ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
8820ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	rc = __mv_stop_dma(ap);
8830ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
8840ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8850ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	return rc;
8860ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik}
8870ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8888a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#ifdef ATA_DEBUG
88931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_mem(void __iomem *start, unsigned bytes)
89020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
89131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
89231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
89331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%p: ", start + b);
89431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
8952dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			printk("%08x ", readl(start + b));
89631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
89731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
89831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
89931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
90031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
9018a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#endif
9028a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik
90331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
90431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
90531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
90631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
90731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 dw;
90831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
90931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%02x: ", b);
91031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
9112dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			(void) pci_read_config_dword(pdev, b, &dw);
9122dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			printk("%08x ", dw);
91331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
91431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
91531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
91631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
91731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
91831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
91931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_all_regs(void __iomem *mmio_base, int port,
92031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			     struct pci_dev *pdev)
92131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
92231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
9238b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	void __iomem *hc_base = mv_hc_base(mmio_base,
92431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ					   port >> MV_PORT_HC_SHIFT);
92531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_base;
92631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int start_port, num_ports, p, start_hc, num_hcs, hc;
92731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
92831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (0 > port) {
92931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = start_port = 0;
93031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = 8;		/* shld be benign for 4 port devs */
93131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_hcs = 2;
93231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	} else {
93331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = port >> MV_PORT_HC_SHIFT;
93431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_port = port;
93531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = num_hcs = 1;
93631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
9378b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
93831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports > 1 ? num_ports - 1 : start_port);
93931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
94031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (NULL != pdev) {
94131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("PCI config space regs:\n");
94231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_pci_cfg(pdev, 0x68);
94331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
94431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	DPRINTK("PCI regs:\n");
94531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xc00, 0x3c);
94631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xd00, 0x34);
94731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xf00, 0x4);
94831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0x1d00, 0x6c);
94931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
950d220c37e0a3c9a47ae00e87e044d963b3ea040bcDan Aloni		hc_base = mv_hc_base(mmio_base, hc);
95131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("HC regs (HC %i):\n", hc);
95231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(hc_base, 0x1c);
95331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
95431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (p = start_port; p < start_port + num_ports; p++) {
95531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port_base = mv_port_base(mmio_base, p);
9562dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		DPRINTK("EDMA regs (port %i):\n", p);
95731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base, 0x54);
9582dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		DPRINTK("SATA regs (port %i):\n", p);
95931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base+0x300, 0x60);
96031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
96131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
96220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
96320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
96420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic unsigned int mv_scr_offset(unsigned int sc_reg_in)
96520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
96620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs;
96720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
96820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	switch (sc_reg_in) {
96920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_STATUS:
97020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_CONTROL:
97120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ERROR:
97220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
97320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
97420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ACTIVE:
97520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
97620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
97720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	default:
97820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = 0xffffffffU;
97920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
98020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
98120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return ofs;
98220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
98320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
984da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
98520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
98620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
98720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
988da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
989da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(mv_ap_base(ap) + ofs);
990da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
991da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
992da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
99320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
99420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
995da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
99620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
99720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
99820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
999da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
100020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		writelfl(val, mv_ap_base(ap) + ofs);
1001da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1002da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1003da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
100420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
100520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1006c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
1007c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			void __iomem *port_mmio)
1008e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1009e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
1010e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1011e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* set up non-NCQ EDMA configuration */
1012c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	cfg &= ~(1 << 9);	/* disable eQue */
1013e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1014e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	if (IS_GEN_I(hpriv)) {
1015e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1016e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 8);	/* enab config burst size mask */
1017e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1018e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1019e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	else if (IS_GEN_II(hpriv)) {
1020e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1021e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
1022e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
1023e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1024e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1025e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	else if (IS_GEN_IIE(hpriv)) {
1026e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
1027e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
1028e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
1029e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 18);	/* enab early completion */
1030e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
1031e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
10324537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		cfg &= ~(EDMA_CFG_NCQ);	/* clear NCQ */
1033e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
1034e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1035e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
1036e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1037e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
103805b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
103905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_start - Port specific init/start routine.
104005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
104105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
104205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Allocate and point to DMA memory, init port private memory,
104305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      zero indices.
104405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
104505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
104605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
104705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
104831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap)
104931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1050cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct device *dev = ap->host->dev;
1051cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
105231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp;
105331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
105431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void *mem;
105531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t mem_dma;
10560ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
105724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	int rc;
105831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
105924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
10606037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!pp)
106124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
106231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
106324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
106424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo				  GFP_KERNEL);
10656037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!mem)
106624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
106731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
106831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10696037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	rc = ata_pad_alloc(ap, dev);
10706037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (rc)
107124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
10726037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik
10738b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* First item in chunk of DMA memory:
107431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command request table (CRQB), 32 bytes each in size
107531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
107631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb = mem;
107731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb_dma = mem_dma;
107831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRQB_Q_SZ;
107931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRQB_Q_SZ;
108031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10818b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* Second item:
108231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command response table (CRPB), 8 bytes each in size
108331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
108431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb = mem;
108531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb_dma = mem_dma;
108631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRPB_Q_SZ;
108731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRPB_Q_SZ;
108831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
108931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Third item:
109031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
109131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
109231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl = mem;
109331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl_dma = mem_dma;
109431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10950ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
10960ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
1097c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_edma_cfg(ap, hpriv, port_mmio);
1098e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1099c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_set_edma_ptrs(port_mmio, hpriv, pp);
110031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11010ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
11020ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
110331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Don't turn on EDMA here...do it before DMA commands only.  Else
110431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * we'll be unable to send non-data, PIO, etc due to restricted access
110531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * to shadow regs.
110631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
110731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	ap->private_data = pp;
110831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
110931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
111031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
111105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
111205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_stop - Port specific cleanup/stop routine.
111305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
111405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
111505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Stop DMA, cleanup port memory.
111605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
111705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
1118cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine uses the host lock to protect the DMA stop.
111905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
112031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap)
112131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
112231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_stop_dma(ap);
112331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
112431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
112505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
112605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
112705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command whose SG list to source from
112805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
112905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Populate the SG list and mark the last entry.
113005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
113105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
113205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
113305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
11346c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzikstatic void mv_fill_sg(struct ata_queued_cmd *qc)
113531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
113631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = qc->ap->private_data;
1137972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	struct scatterlist *sg;
11383be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	struct mv_sg *mv_sg, *last_sg = NULL;
113931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1140d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	mv_sg = pp->sg_tbl;
1141972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	ata_for_each_sg(sg, qc) {
1142d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		dma_addr_t addr = sg_dma_address(sg);
1143d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		u32 sg_len = sg_dma_len(sg);
114422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
11454007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		while (sg_len) {
11464007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 offset = addr & 0xffff;
11474007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 len = sg_len;
114822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
11494007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			if ((offset + sg_len > 0x10000))
11504007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson				len = 0x10000 - offset;
11514007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11524007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
11534007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
11546c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik			mv_sg->flags_size = cpu_to_le32(len & 0xffff);
11554007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11564007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			sg_len -= len;
11574007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			addr += len;
11584007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11593be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik			last_sg = mv_sg;
11604007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg++;
11614007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		}
116231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
11633be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik
11643be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	if (likely(last_sg))
11653be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik		last_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
116631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
116731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11685796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
116931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1170559eedad7f7764dacca33980127b4615011230e4Mark Lord	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
117131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		(last ? CRQB_CMD_LAST : 0);
1172559eedad7f7764dacca33980127b4615011230e4Mark Lord	*cmdw = cpu_to_le16(tmp);
117331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
117431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
117505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
117605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_prep - Host specific command preparation.
117705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to prepare
117805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
117905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
118005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it handles prep of the CRQB
118105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      (command request block), does some sanity checking, and calls
118205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the SG load routine.
118305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
118405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
118505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
118605b308e1df6d9d673daedb517969241f41278b52Brett Russ */
118731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc)
118831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
118931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_port *ap = qc->ap;
119031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = ap->private_data;
1191e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16 *cw;
119231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_taskfile *tf;
119331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u16 flags = 0;
1194a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
119531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11962dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	if (qc->tf.protocol != ATA_PROT_DMA)
119731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
119820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
119931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Fill in command request block
120031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
1201e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
120231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		flags |= CRQB_FLAG_READ;
1203beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
120431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	flags |= qc->tag << CRQB_TAG_SHIFT;
12054537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* 50xx appears to ignore this*/
120631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1207bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1208bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1209a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1210a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr =
121131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1212a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr_hi =
121331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1214a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
121531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1216a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	cw = &pp->crqb[in_index].ata_cmd[0];
121731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	tf = &qc->tf;
121831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
121931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Sadly, the CRQB cannot accomodate all registers--there are
122031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * only 11 bytes...so we must pick and choose required
122131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * registers based on the command.  So, we drop feature and
122231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * hob_feature for [RW] DMA commands, but they are needed for
122331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * NCQ.  NCQ will drop hob_nsect.
122420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
122531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	switch (tf->command) {
122631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ:
122731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ_EXT:
122831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE:
122931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE_EXT:
1230c15d85c8f3f73b5f20aae7928e25b6996f16b328Jens Axboe	case ATA_CMD_WRITE_FUA_EXT:
123131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
123231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
123331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
123431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_READ:
123531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_WRITE:
12368b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
123731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
123831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
123931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif				/* FIXME: remove this line when NCQ added */
124031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	default:
124131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* The only other commands EDMA supports in non-queued and
124231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
124331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * of which are defined/used by Linux.  If we get here, this
124431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * driver needs work.
124531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 *
124631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * FIXME: modify libata to give qc_prep a return value and
124731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * return error here.
124831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
124931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		BUG_ON(tf->command);
125031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
125131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
125231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
125331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
125431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
125531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
125631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
125731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
125831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
125931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
126031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
126131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1262e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1263e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1264e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	mv_fill_sg(qc);
1265e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1266e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1267e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik/**
1268e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      mv_qc_prep_iie - Host specific command preparation.
1269e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      @qc: queued command to prepare
1270e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1271e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      This routine simply redirects to the general purpose routine
1272e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      if command is not DMA.  Else, it handles prep of the CRQB
1273e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      (command request block), does some sanity checking, and calls
1274e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      the SG load routine.
1275e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1276e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      LOCKING:
1277e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      Inherited from caller.
1278e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik */
1279e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1280e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1281e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_port *ap = qc->ap;
1282e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_port_priv *pp = ap->private_data;
1283e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_crqb_iie *crqb;
1284e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_taskfile *tf;
1285a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
1286e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 flags = 0;
1287e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
12882dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	if (qc->tf.protocol != ATA_PROT_DMA)
1289e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1290e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1291e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* Fill in Gen IIE command request block
1292e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	 */
1293e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1294e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		flags |= CRQB_FLAG_READ;
1295e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1296beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1297e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	flags |= qc->tag << CRQB_TAG_SHIFT;
1298bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* "I/O Id" is -really-
12994537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik						   what we use as our tag */
1300e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1301bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1302bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1303a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1304a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1305e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1306e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1307e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->flags = cpu_to_le32(flags);
1308e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1309e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	tf = &qc->tf;
1310e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[0] = cpu_to_le32(
1311e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->command << 16) |
1312e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->feature << 24)
1313e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1314e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[1] = cpu_to_le32(
1315e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbal << 0) |
1316e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbam << 8) |
1317e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbah << 16) |
1318e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->device << 24)
1319e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1320e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[2] = cpu_to_le32(
1321e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbal << 0) |
1322e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbam << 8) |
1323e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbah << 16) |
1324e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_feature << 24)
1325e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1326e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[3] = cpu_to_le32(
1327e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->nsect << 0) |
1328e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_nsect << 8)
1329e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1330e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1331e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
133231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
133331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_fill_sg(qc);
133431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
133531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
133605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
133705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_issue - Initiate a command to the host
133805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to start
133905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
134005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
134105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it sanity checks our local
134205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      caches of the request producer/consumer indices then enables
134305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      DMA and bumps the request producer index.
134405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
134505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
134605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
134705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
13489a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
134931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1350c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct ata_port *ap = qc->ap;
1351c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1352c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1353c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1354bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 in_index;
135531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1356c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (qc->tf.protocol != ATA_PROT_DMA) {
135731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* We're about to send a non-EDMA capable command to the
135831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * port.  Turn off EDMA so there won't be problems accessing
135931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * shadow block, etc registers.
136031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
13610ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		__mv_stop_dma(ap);
136231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return ata_qc_issue_prot(qc);
136331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
136431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1365bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_start_dma(port_mmio, hpriv, pp);
1366bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1367bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
136831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
136931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* until we do queuing, the queue should be empty at this point */
1370a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1371a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
137231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1373bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	pp->req_idx++;
137431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1375bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
137631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
137731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and write the request in pointer to kick the EDMA to life */
1378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
1379bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
138031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
138131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
138231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
138331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
138405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
138505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_err_intr - Handle error interrupts on the port
138605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
13879b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord *      @reset_allowed: bool: 0 == don't trigger from reset here
138805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
138905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      In most cases, just clear the interrupt and move on.  However,
139005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      some cases require an eDMA reset, which is done right before
139105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the COMRESET in mv_phy_reset().  The SERR case requires a
139205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      clear of pending errors in the SATA SERROR register.  Finally,
139305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if the port disabled DMA, update our cached copy to match.
139405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
139505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
139605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
139705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1398bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
139931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
140031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
1401bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 edma_err_cause, eh_freeze_mask, serr = 0;
1402bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1403bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1404bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
1405bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int action = 0, err_mask = 0;
14069af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_eh_info *ehi = &ap->link.eh_info;
140720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1408bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_clear_desc(ehi);
140920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1410bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!edma_enabled) {
1411bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* just a guess: do we need to do this? should we
1412bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * expand this, and do it in all cases?
1413bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1414936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_read(&ap->link, SCR_ERROR, &serr);
1415936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
141620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1417bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1418bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1420bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
1421bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/*
1423bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * all generations share these EDMA error cause bits
1424bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
1425bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1426bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & EDMA_ERR_DEV)
1427bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_DEV;
1428bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
14296c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
1430bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			EDMA_ERR_INTRL_PAR)) {
1431bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_ATA_BUS;
1432bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1433b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo		ata_ehi_push_desc(ehi, "parity error");
1434bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1435bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
1436bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_hotplugged(ehi);
1437bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
1438b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			"dev disconnect" : "dev connect");
1439bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1440bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1441ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv)) {
1442bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE_5;
1443bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1444bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
1445bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1446bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1447b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1448bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1449bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	} else {
1450bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE;
1451bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1452bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
1453bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1454bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1455b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1456bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1457bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1458bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SERR) {
1459936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo			sata_scr_read(&ap->link, SCR_ERROR, &serr);
1460936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo			sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
1461bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_ATA_BUS;
1462bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			action |= ATA_EH_HARDRESET;
1463bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1464afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
146520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
146620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Clear EDMA now that SERR cleanup done */
146720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
146820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1469bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!err_mask) {
1470bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask = AC_ERR_OTHER;
1471bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1472bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1474bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->serror |= serr;
1475bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->action |= action;
1476bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1477bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc)
1478bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		qc->err_mask |= err_mask;
1479bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1480bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehi->err_mask |= err_mask;
1481bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1482bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & eh_freeze_mask)
1483bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_freeze(ap);
1484bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1485bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_abort(ap);
1486bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1487bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1488bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_pio(struct ata_port *ap)
1489bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1490bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1491bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u8 ata_status;
1492bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1493bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* ignore spurious intr if drive still BUSY */
1494bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_status = readb(ap->ioaddr.status_addr);
1495bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(ata_status & ATA_BUSY))
1496bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1497bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1498bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get active ATA command */
14999af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	qc = ata_qc_from_tag(ap, ap->link.active_tag);
1500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(!qc))			/* no active tag */
1501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1502bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc->tf.flags & ATA_TFLAG_POLLING)	/* polling; we don't own qc */
1503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* and finally, complete the ATA command */
1506bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	qc->err_mask |= ac_err_mask(ata_status);
1507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_qc_complete(qc);
1508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1510bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_edma(struct ata_port *ap)
1511bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1512bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1513bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1514bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1515bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1516bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 out_index, in_index;
1517bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	bool work_done = false;
1518bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1519bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get h/w response queue pointer */
1520bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1521bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1522bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1523bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	while (1) {
1524bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		u16 status;
15256c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		unsigned int tag;
1526bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1527bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* get s/w response queue last-read pointer, and compare */
1528bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
1529bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (in_index == out_index)
1530bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
1531bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1532bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* 50xx: get active ATA command */
15330ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		if (IS_GEN_I(hpriv))
15349af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			tag = ap->link.active_tag;
1535bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15366c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		/* Gen II/IIE: get active ATA command via tag, to enable
15376c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * support for queueing.  this works transparently for
15386c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * queued and non-queued modes.
1539bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
15406c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else if (IS_GEN_II(hpriv))
15416c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15426c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_6) & 0x3f;
1543bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15446c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else /* IS_GEN_IIE */
15456c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15466c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_7) & 0x3f;
1547bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15486c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		qc = ata_qc_from_tag(ap, tag);
1549bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1550bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
1551bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * bits (WARNING: might not necessarily be associated
1552bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * with this command), which -should- be clear
1553bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * if all is well
1554bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1555bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		status = le16_to_cpu(pp->crpb[out_index].flags);
1556bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(status & 0xff)) {
1557bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1558bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			return;
1559bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1560bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1561bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* and finally, complete the ATA command */
1562bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (qc) {
1563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			qc->err_mask |=
1564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
1565bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_qc_complete(qc);
1566bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1567bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15680ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		/* advance software response queue pointer, to
1569bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * indicate (after the loop completes) to hardware
1570bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * that we have consumed a response queue entry.
1571bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1572bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		work_done = true;
1573bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->resp_idx++;
1574bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1575bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1576bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (work_done)
1577bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
1578bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 (out_index << EDMA_RSP_Q_PTR_SHIFT),
1579bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
158020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
158120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
158205b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
158305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_host_intr - Handle all interrupts on the given host controller
1584cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      @host: host specific structure
158505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @relevant: port error bits relevant to this host controller
158605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @hc: which host controller we're to look at
158705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
158805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read then write clear the HC interrupt status then walk each
158905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port connected to the HC and see if it needs servicing.  Port
159005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      success ints are reported in the HC interrupt status reg, the
159105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port error ints are reported in the higher level main
159205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt status register and thus are passed in via the
159305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      'relevant' argument.
159405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
159505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
159605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
159705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1598cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
159920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
16000d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
160120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
160220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 hc_irq_cause;
1603c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int port, port0;
160420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1605351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (hc == 0)
160620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = 0;
1607351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	else
160820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = MV_PORTS_PER_HC;
160920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
161020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* we'll need the HC success int register in most cases */
161120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
1612bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!hc_irq_cause)
1613bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1614bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1615bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
161620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
161720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
16182dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		hc, relevant, hc_irq_cause);
161920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
162020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
1621cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		struct ata_port *ap = host->ports[port];
162263af2a5c5990d95f1e7d8795f1425fb976ea2b4bMark Lord		struct mv_port_priv *pp = ap->private_data;
1623bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		int have_err_bits, hard_port, shift;
162455d8ca4f8094246da6e71889a4e04bfafaa78b10Jeff Garzik
1625bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
1626a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik			continue;
1627a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik
162831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		shift = port << 1;		/* (port * 2) */
162920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (port >= MV_PORTS_PER_HC) {
163020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ			shift++;	/* skip bit 8 in the HC Main IRQ reg */
163120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
1632bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		have_err_bits = ((PORT0_ERR << shift) & relevant);
1633bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1634bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(have_err_bits)) {
1635bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct ata_queued_cmd *qc;
16368b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
16379af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1638bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
1639bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				continue;
1640bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1641bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1642bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			continue;
1643bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1644bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1645bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1646bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1647bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1648bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
1649bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_edma(ap);
1650bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		} else {
1651bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((DEV_IRQ << hard_port) & hc_irq_cause)
1652bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_pio(ap);
165320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
165420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
165520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("EXIT\n");
165620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
165720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1658bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_pci_error(struct ata_host *host, void __iomem *mmio)
1659bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
166002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_host_priv *hpriv = host->private_data;
1661bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_port *ap;
1662bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1663bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_info *ehi;
1664bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int i, err_mask, printed = 0;
1665bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 err_cause;
1666bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
166702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	err_cause = readl(mmio + hpriv->irq_cause_ofs);
1668bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1669bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
1670bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		   err_cause);
1671bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1672bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	DPRINTK("All regs @ PCI error\n");
1673bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1674bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
167502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	writelfl(0, mmio + hpriv->irq_cause_ofs);
1676bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1677bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	for (i = 0; i < host->n_ports; i++) {
1678bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ap = host->ports[i];
1679936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		if (!ata_link_offline(&ap->link)) {
16809af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			ehi = &ap->link.eh_info;
1681bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_ehi_clear_desc(ehi);
1682bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (!printed++)
1683bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ata_ehi_push_desc(ehi,
1684bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik					"PCI err cause 0x%08x", err_cause);
1685bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_HOST_BUS;
1686bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ehi->action = ATA_EH_HARDRESET;
16879af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1688bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc)
1689bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				qc->err_mask |= err_mask;
1690bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			else
1691bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ehi->err_mask |= err_mask;
1692bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1693bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_port_freeze(ap);
1694bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1695bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1696bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1697bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
169805b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
1699c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik *      mv_interrupt - Main interrupt event handler
170005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @irq: unused
170105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @dev_instance: private data; in this case the host structure
170205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
170305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read the read only register to determine if any host
170405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      controllers have pending interrupts.  If so, call lower level
170505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      routine to handle.  Also check for PCI errors which are only
170605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      reported here.
170705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
17088b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik *      LOCKING:
1709cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine holds the host lock while processing pending
171005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts.
171105b308e1df6d9d673daedb517969241f41278b52Brett Russ */
17127d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mv_interrupt(int irq, void *dev_instance)
171320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
1714cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
171520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int hc, handled = 0, n_hcs;
17160d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
171720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 irq_stat;
171820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
171920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
172020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
172120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* check the cases where we either have nothing pending or have read
172220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 * a bogus register value which can indicate HW removal or PCI fault
172320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
1724351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (!irq_stat || (0xffffffffU == irq_stat))
172520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return IRQ_NONE;
172620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1727cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	n_hcs = mv_get_hc_count(host->ports[0]->flags);
1728cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_lock(&host->lock);
172920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1730bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(irq_stat & PCI_ERR)) {
1731bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_pci_error(host, mmio);
1732bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		handled = 1;
1733bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		goto out_unlock;	/* skip all other HC irq handling */
1734bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1735bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
173620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hcs; hc++) {
173720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
173820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (relevant) {
1739cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik			mv_host_intr(host, relevant, hc);
1740bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			handled = 1;
174120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
174220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1743615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
1744bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikout_unlock:
1745cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
174620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
174720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return IRQ_RETVAL(handled);
174820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
174920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1750c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1751c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1752c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1753c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1754c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1755c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return hc_mmio + ofs;
1756c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1757c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1758c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1759c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1760c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs;
1761c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1762c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	switch (sc_reg_in) {
1763c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_STATUS:
1764c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_ERROR:
1765c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_CONTROL:
1766c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = sc_reg_in * sizeof(u32);
1767c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1768c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	default:
1769c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = 0xffffffffU;
1770c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1771c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1772c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return ofs;
1773c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1774c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1775da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
1776c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
17770d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
17780d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1779c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1780c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1781da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1782da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(addr + ofs);
1783da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1784da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1785da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1786c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1787c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1788da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1789c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
17900d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
17910d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1792c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1793c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1794da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
17950d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writelfl(val, addr + ofs);
1796da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1797da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1798da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1799c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1800c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1801522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1802522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1803522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	int early_5080;
1804522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
180544c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
1806522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1807522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	if (!early_5080) {
1808522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1809522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		tmp |= (1 << 0);
1810522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1811522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	}
1812522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1813522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	mv_reset_pci_bus(pdev, mmio);
1814522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1815522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1816522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1817522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1818522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1819522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1820522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
182147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1822ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
1823ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1824c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1825c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1826c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1827c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1828c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1829c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1830c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1831ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1832ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
183347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1834ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1835522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	u32 tmp;
1836522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1837522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0, mmio + MV_GPIO_PORT_CTL);
1838522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1839522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1840522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1841522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1842522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp |= ~(1 << 0);
1843522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1844ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1845ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
18462a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
18472a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
1848bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
1849c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1850c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1851c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1852c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1853c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1854c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	if (fix_apm_sq) {
1855c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_LT_MODE);
1856c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= (1 << 19);
1857c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_LT_MODE);
1858c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1859c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_PHY_CTL);
1860c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp &= ~0x3;
1861c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= 0x1;
1862c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_PHY_CTL);
1863c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1864c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1865c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1866c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= ~mask;
1867c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].pre;
1868c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].amps;
1869c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, phy_mmio + MV5_PHY_MODE);
1870bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
1871bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
1872c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1873c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1874c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, port_mmio + (reg))
1875c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1876c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port)
1877c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1878c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
1879c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1880c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1881c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1882c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	mv_channel_reset(hpriv, mmio, port);
1883c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1884c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x028);	/* command */
1885c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1886c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x004);	/* timer */
1887c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x008);	/* irq err cause */
1888c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);	/* irq err mask */
1889c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);	/* rq bah */
1890c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);	/* rq inp */
1891c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);	/* rq outp */
1892c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x01c);	/* respq bah */
1893c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x024);	/* respq outp */
1894c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x020);	/* respq inp */
1895c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x02c);	/* test control */
1896c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1897c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1898c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1899c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1900c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, hc_mmio + (reg))
1901c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1902c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int hc)
190347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik{
1904c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1905c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1906c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1907c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);
1908c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);
1909c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);
1910c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);
1911c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1912c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(hc_mmio + 0x20);
1913c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= 0x1c1c1c1c;
1914c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= 0x03030303;
1915c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, hc_mmio + 0x20);
1916c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1917c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1918c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1919c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1920c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1921c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1922c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int hc, port;
1923c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1924c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	for (hc = 0; hc < n_hc; hc++) {
1925c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		for (port = 0; port < MV_PORTS_PER_HC; port++)
1926c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			mv5_reset_hc_port(hpriv, mmio,
1927c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik					  (hc * MV_PORTS_PER_HC) + port);
1928c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1929c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mv5_reset_one_hc(hpriv, mmio, hc);
1930c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1931c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1932c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return 0;
193347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik}
193447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
1935101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1936101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#define ZERO(reg) writel(0, mmio + (reg))
1937101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1938101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
193902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct ata_host     *host = dev_get_drvdata(&pdev->dev);
194002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_host_priv *hpriv = host->private_data;
1941101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1942101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1943101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_PCI_MODE);
1944101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0xff00ffff;
1945101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_PCI_MODE);
1946101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1947101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_DISC_TIMER);
1948101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_MSI_TRIGGER);
1949101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1950101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(HC_MAIN_IRQ_MASK_OFS);
1951101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_SERR_MASK);
195202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	ZERO(hpriv->irq_cause_ofs);
195302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	ZERO(hpriv->irq_mask_ofs);
1954101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_LOW_ADDRESS);
1955101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1956101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_ATTRIBUTE);
1957101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_COMMAND);
1958101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1959101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1960101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1961101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1962101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1963101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1964101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1965101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	mv5_reset_flash(hpriv, mmio);
1966101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1967101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_GPIO_PORT_CTL);
1968101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0x3;
1969101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp |= (1 << 5) | (1 << 6);
1970101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_GPIO_PORT_CTL);
1971101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1972101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1973101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik/**
1974101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      mv6_reset_hc - Perform the 6xxx global soft reset
1975101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      @mmio: base address of the HBA
1976101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1977101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      This routine only applies to 6xxx parts.
1978101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1979101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      LOCKING:
1980101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      Inherited from caller.
1981101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik */
1982c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1983c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1984101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1985101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1986101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	int i, rc = 0;
1987101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 t;
1988101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1989101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* Following procedure defined in PCI "main command and status
1990101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 * register" table.
1991101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 */
1992101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	t = readl(reg);
1993101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(t | STOP_PCI_MASTER, reg);
1994101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1995101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	for (i = 0; i < 1000; i++) {
1996101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
1997101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
19982dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		if (PCI_MASTER_EMPTY & t)
1999101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik			break;
2000101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2001101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(PCI_MASTER_EMPTY & t)) {
2002101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
2003101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2004101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2005101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2006101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2007101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* set reset */
2008101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2009101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2010101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t | GLOB_SFT_RST, reg);
2011101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2012101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2013101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
2014101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2015101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(GLOB_SFT_RST & t)) {
2016101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
2017101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2018101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2019101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2020101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2021101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
2022101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2023101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2024101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
2025101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2026101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2027101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while ((GLOB_SFT_RST & t) && (i-- > 0));
2028101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2029101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (GLOB_SFT_RST & t) {
2030101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
2031101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2032101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2033101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikdone:
2034101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	return rc;
2035101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2036101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
203747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
2038ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
2039ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
2040ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	void __iomem *port_mmio;
2041ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	u32 tmp;
2042ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2043ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(mmio + MV_RESET_CFG);
2044ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	if ((tmp & (1 << 0)) == 0) {
204547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->signal[idx].amps = 0x7 << 8;
2046ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		hpriv->signal[idx].pre = 0x1 << 5;
2047ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		return;
2048ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	}
2049ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2050ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	port_mmio = mv_port_base(mmio, idx);
2051ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(port_mmio + PHY_MODE2);
2052ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2053ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
2054ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
2055ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2056ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
205747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
2058ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
205947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
2060ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2061ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2062c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
20632a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
2064bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
2065c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
2066c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2067bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
206847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	int fix_phy_mode2 =
206947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
2070bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	int fix_phy_mode4 =
207147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
207247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	u32 m2, tmp;
207347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
207447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (fix_phy_mode2) {
207547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
207647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~(1 << 16);
207747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 |= (1 << 31);
207847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
207947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
208147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
208347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~((1 << 16) | (1 << 31));
208447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
208547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
208747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	}
208847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* who knows what this magic does */
209047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp = readl(port_mmio + PHY_MODE3);
209147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp &= ~0x7F800000;
209247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp |= 0x2A800000;
209347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(tmp, port_mmio + PHY_MODE3);
2094bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2095bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (fix_phy_mode4) {
209647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		u32 m4;
2097bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2098bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = readl(port_mmio + PHY_MODE4);
209947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
210047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
210147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			tmp = readl(port_mmio + 0x310);
2102bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2103bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = (m4 & ~(1 << 1)) | (1 << 0);
2104bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2105bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		writel(m4, port_mmio + PHY_MODE4);
210647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
210747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
210847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			writel(tmp, port_mmio + 0x310);
2109bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2110bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2111bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	/* Revert values of pre-emphasis and signal amps to the saved ones */
2112bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 = readl(port_mmio + PHY_MODE2);
2113bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2114bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 &= ~MV_M2_PREAMP_MASK;
21152a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].amps;
21162a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].pre;
211747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	m2 &= ~(1 << 16);
2118bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2119e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* according to mvSata 3.6.1, some IIE values are fixed */
2120e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (IS_GEN_IIE(hpriv)) {
2121e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 &= ~0xC30FF01F;
2122e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 |= 0x0000900F;
2123e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
2124e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2125bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	writel(m2, port_mmio + PHY_MODE2);
2126bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2127bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2128c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
2129c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no)
2130c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
2131c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port_no);
2132c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2133c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
2134c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2135ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv)) {
2136c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2137eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl |= (1 << 7);		/* enable gen2i speed */
2138eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2139c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2140c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
2141c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2142c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	udelay(25);		/* allow reset propagation */
2143c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2144c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	/* Spec never mentions clearing the bit.  Marvell's driver does
2145c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 * clear the bit, however.
2146c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 */
2147c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(0, port_mmio + EDMA_CMD_OFS);
2148c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2149c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->ops->phy_errata(hpriv, mmio, port_no);
2150c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2151ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2152c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mdelay(1);
2153c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
2154c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
215505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
2156bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik *      mv_phy_reset - Perform eDMA reset followed by COMRESET
215705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
215805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
215905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Part of this is taken from __sata_phy_reset and modified to
216005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      not sleep since this routine gets called from interrupt level.
216105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
216205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
216305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.  This is coded to safe to call at
216405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt level, i.e. it does not sleep.
216531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ */
2166bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_phy_reset(struct ata_port *ap, unsigned int *class,
2167bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 unsigned long deadline)
216820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2169095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2170cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
217120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
217222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	int retry = 5;
217322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	u32 sstatus;
217420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
217520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
217620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2177da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2178da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2179da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2180da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2181da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2182da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2183da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2184da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
21852d79ab8fd7a7bf3a45d0e948ae27b3dd95ce95eaSaeed Bishara			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2186da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2187da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
218820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
218922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* Issue COMRESET via SControl */
219022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzikcomreset_retry:
2191936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
2192bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(1);
219322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2194936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
2195bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(20);
219622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
219731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	do {
2198936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
219962f1d0e6de138b91d55fbd7d579c837ed62e9e31Andres Salomon		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
220031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
220122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2202bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(1);
2203c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	} while (time_before(jiffies, deadline));
220420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
220522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* work around errata */
2206ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv) &&
220722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
220822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (retry-- > 0))
220922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		goto comreset_retry;
2210095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2211da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2212da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2213da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2214da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2215da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2216da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2217da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2218da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
2219da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2220da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2221da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
222231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2223936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	if (ata_link_offline(&ap->link)) {
2224bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		*class = ATA_DEV_NONE;
222520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return;
222620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
222720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
222822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* even after SStatus reflects that device is ready,
222922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * it seems to take a while for link to be fully
223022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * established (and thus Status no longer 0x80/0x7F),
223122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * so we poll a bit for that, here.
223222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 */
223322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	retry = 20;
223422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	while (1) {
223522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		u8 drv_stat = ata_check_status(ap);
223622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
223722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2238bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(500);
223922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if (retry-- <= 0)
224022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2241bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (time_after(jiffies, deadline))
2242bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
224322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	}
224422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2245bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: if we passed the deadline, the following
2246bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * code probably produces an invalid result
2247bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
224820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2249bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* finally, read device signature from TF registers */
22503f19859ee95a38c066a0420eb8a30c76ecd67a42Tejun Heo	*class = ata_dev_try_classify(ap->link.device, 1, NULL);
2251095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2252095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2253095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2254bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
2255095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2256bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	VPRINTK("EXIT\n");
225720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
225820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2259cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic int mv_prereset(struct ata_link *link, unsigned long deadline)
226022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik{
2261cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2262bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2263cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_eh_context *ehc = &link->eh_context;
2264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	int rc;
22650ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
2266bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	rc = mv_stop_dma(ap);
2267bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (rc)
2268bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2270bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) {
2271bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
2272bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2273bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2274bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* if we're about to do hardreset, nothing more to do */
2276bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ehc->i.action & ATA_EH_HARDRESET)
2277bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return 0;
2278bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2279cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	if (ata_link_online(link))
2280bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = ata_wait_ready(ap, deadline);
2281bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
2282bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = -ENODEV;
2283bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2284bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return rc;
228522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik}
228622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2287cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic int mv_hardreset(struct ata_link *link, unsigned int *class,
2288bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			unsigned long deadline)
228931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
2290cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2291bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
22920d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
229331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2294bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(ap);
229531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2296bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_channel_reset(hpriv, mmio, ap->port_no);
229731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2298bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_phy_reset(ap, class, deadline);
2299bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2300bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return 0;
2301bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2302bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2303cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic void mv_postreset(struct ata_link *link, unsigned int *classes)
2304bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2305cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2306bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 serr;
2307bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2308bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* print link status */
2309cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_print_link_status(link);
231031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2311bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear SError */
2312cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_scr_read(link, SCR_ERROR, &serr);
2313cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_scr_write_flush(link, SCR_ERROR, serr);
2314bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2315bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* bail out if no device is present */
2316bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
2317bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		DPRINTK("EXIT, no device\n");
2318bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
23199b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord	}
2320bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2321bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* set up device control */
2322bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
2323bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2324bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2325bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap)
2326bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2327bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_do_eh(ap, mv_prereset, ata_std_softreset,
2328bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		  mv_hardreset, mv_postreset);
2329bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2330bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2331bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc)
2332bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2333bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(qc->ap);
2334bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2335bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2336bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(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	u32 tmp, mask;
2341bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift;
2342bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2343bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2344bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2345bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2346bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0)
2347bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2348bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2349bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2350bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2351bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* disable assertion of portN err, done events */
2352bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2353bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
2354bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2355bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2356bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap)
2357bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2358bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2359bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2360bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2361bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
2362bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask, hc_irq_cause;
2363bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift, hc_port_no = ap->port_no;
2364bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2365bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2366bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2367bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2368bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0) {
2369bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2370bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hc_port_no -= 4;
2371bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2372bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2373bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2374bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2375bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear EDMA errors on this port */
2376bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2377bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear pending irq events */
2379bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
2380bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << hc_port_no);	/* clear CRPB-done */
2381bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
2382bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
2383bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2384bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* enable assertion of portN err, done events */
2385bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2386bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
238731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
238831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
238905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
239005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_init - Perform some early initialization on a single port.
239105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port: libata data structure storing shadow register addresses
239205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port_mmio: base address of the port
239305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
239405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Initialize shadow register mmio addresses, clear outstanding
239505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts on the port, and unmask interrupts for the future
239605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      start of the port.
239705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
239805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
239905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
240005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
240131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
240220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
24030d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
240431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	unsigned serr_ofs;
240531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
24068b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* PIO related setup
240731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
240831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
24098b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->error_addr =
241031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
241131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
241231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
241331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
241431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
241531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
24168b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->status_addr =
241731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
241831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* special case: control/altstatus doesn't have ATA_REG_ address */
241931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
242031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
242131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* unused: */
24228d9db2d2fbae9e05022825c32f86e00c8e342860Randy Dunlap	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
242320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
242431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding port interrupt conditions */
242531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	serr_ofs = mv_scr_offset(SCR_ERROR);
242631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
242731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
242831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
242920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* unmask all EDMA error interrupts */
243031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
243120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24328b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
243331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_CFG_OFS),
243431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
243531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
243620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
243720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24384447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2439bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
24404447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
24414447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2442bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
2443bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
24445796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	switch (board_idx) {
244547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	case chip_5080:
244647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2447ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
244847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
244944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
245047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x1:
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 50XXB2 workarounds to unknown rev\n");
245947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
246047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
246147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		}
246247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		break;
246347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
2464bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_504x:
2465bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_508x:
246647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2467ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
2468bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
246944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
247047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x0:
247147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
247247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
247347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
247447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
247547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
247647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
247747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
247847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying B2 workarounds to unknown rev\n");
247947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
248047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
2481bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2482bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2483bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2484bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_604x:
2485bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_608x:
248647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv6xxx_ops;
2487ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_II;
248847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
248944c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
249047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x7:
249147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
249247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
249347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x9:
249447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2495bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2496bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		default:
2497bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
249847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik				   "Applying B2 workarounds to unknown rev\n");
249947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
2500bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2501bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2502bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2503bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2504e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_7042:
250502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hp_flags |= MV_HP_PCIE;
2506e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_6042:
2507e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hpriv->ops = &mv6xxx_ops;
2508e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hp_flags |= MV_HP_GEN_IIE;
2509e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
251044c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
2511e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x0:
2512e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_XX42A0;
2513e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2514e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x1:
2515e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2516e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2517e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		default:
2518e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
2519e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			   "Applying 60X1C0 workarounds to unknown rev\n");
2520e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2521e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2522e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		}
2523e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		break;
2524e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2525bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	default:
25265796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik		dev_printk(KERN_ERR, &pdev->dev,
25275796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik			   "BUG: invalid board index %u\n", board_idx);
2528bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		return 1;
2529bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2530bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2531bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	hpriv->hp_flags = hp_flags;
253202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	if (hp_flags & MV_HP_PCIE) {
253302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_cause_ofs	= PCIE_IRQ_CAUSE_OFS;
253402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_mask_ofs	= PCIE_IRQ_MASK_OFS;
253502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->unmask_all_irqs	= PCIE_UNMASK_ALL_IRQS;
253602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	} else {
253702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_cause_ofs	= PCI_IRQ_CAUSE_OFS;
253802a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_mask_ofs	= PCI_IRQ_MASK_OFS;
253902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->unmask_all_irqs	= PCI_UNMASK_ALL_IRQS;
254002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	}
2541bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2542bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	return 0;
2543bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2544bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
254505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
254647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik *      mv_init_host - Perform some early initialization of the host.
25474447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *	@host: ATA host to initialize
25484447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @board_idx: controller index
254905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
255005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      If possible, do an early global reset of the host.  Then do
255105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      our port init and clear/unmask all/relevant host interrupts.
255205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
255305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
255405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
255505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
25564447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_init_host(struct ata_host *host, unsigned int board_idx)
255720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
255820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	int rc = 0, n_hc, port, hc;
25594447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
25604447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
25614447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2562bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
256347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* global interrupt mask */
256447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
256547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
25664447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_chip_id(host, board_idx);
2567bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (rc)
2568bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		goto done;
2569bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25704447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_hc = mv_get_hc_count(host->ports[0]->flags);
2571bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25724447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++)
257347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops->read_preamp(hpriv, port, mmio);
257420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2575c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
257647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (rc)
257720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		goto done;
257820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2579522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_flash(hpriv, mmio);
2580522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_bus(pdev, mmio);
258147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	hpriv->ops->enable_leds(hpriv, mmio);
258220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
25834447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2584ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		if (IS_GEN_II(hpriv)) {
2585c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			void __iomem *port_mmio = mv_port_base(mmio, port);
2586c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
25872a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2588eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl |= (1 << 7);		/* enable gen2i speed */
2589eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
25902a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
25912a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		}
25922a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
2593c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		hpriv->ops->phy_errata(hpriv, mmio, port);
25942a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	}
25952a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
25964447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2597cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		struct ata_port *ap = host->ports[port];
25982a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		void __iomem *port_mmio = mv_port_base(mmio, port);
2599cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		unsigned int offset = port_mmio - mmio;
2600cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
2601cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		mv_port_init(&ap->ioaddr, port_mmio);
2602cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
2603cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
2604cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
260520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
260620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
260720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hc; hc++) {
260831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
260931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
261031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
261131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			"(before clear)=0x%08x\n", hc,
261231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_CFG_OFS),
261331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
261431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
261531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* Clear any currently outstanding hc interrupt conditions */
261631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
261720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
261820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
261931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding host interrupt conditions */
262002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	writelfl(0, mmio + hpriv->irq_cause_ofs);
262131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
262231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and unmask interrupt generation for host regs */
262302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
2624fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik
2625ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2626fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2627fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	else
2628fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
262920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
263020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
26318b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		"PCI int cause/mask=0x%08x/0x%08x\n",
263220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
263320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
263402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		readl(mmio + hpriv->irq_cause_ofs),
263502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		readl(mmio + hpriv->irq_mask_ofs));
2636bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
263731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russdone:
263820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return rc;
263920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
264020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
264105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
264205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_print_info - Dump key info to kernel log for perusal.
26434447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @host: ATA host to print info about
264405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
264505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      FIXME: complete this.
264605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
264705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
264805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
264905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
26504447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic void mv_print_info(struct ata_host *host)
265131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
26524447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
26534447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
265444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	u8 scc;
2655c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	const char *scc_s, *gen;
265631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
265731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Use this to determine the HW stepping of the chip so we know
265831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * what errata to workaround
265931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
266031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
266131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (scc == 0)
266231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "SCSI";
266331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else if (scc == 0x01)
266431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "RAID";
266531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else
2666c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		scc_s = "?";
2667c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik
2668c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	if (IS_GEN_I(hpriv))
2669c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "I";
2670c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_II(hpriv))
2671c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "II";
2672c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_IIE(hpriv))
2673c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "IIE";
2674c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else
2675c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "?";
267631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2677a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	dev_printk(KERN_INFO, &pdev->dev,
2678c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
2679c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
268031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
268131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
268231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
268305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
268405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_init_one - handle a positive probe of a Marvell host
268505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pdev: PCI device found
268605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ent: PCI device ID entry for the matched host
268705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
268805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
268905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
269005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
269120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
269220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
26932dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	static int printed_version;
269420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int board_idx = (unsigned int)ent->driver_data;
26954447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
26964447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
26974447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv;
26984447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int n_ports, rc;
269920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2700a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	if (!printed_version++)
2701a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
270220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27034447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
27044447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
27054447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
27064447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
27074447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
27084447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host || !hpriv)
27094447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
27104447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->private_data = hpriv;
27114447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
27124447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* acquire resources */
271324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
271424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
271520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return rc;
271620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27170d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
27180d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
271924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
27200d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
272124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
27224447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
272320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2724d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	rc = pci_go_64(pdev);
2725d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (rc)
2726d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		return rc;
2727d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
272820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* initialize adapter */
27294447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_init_host(host, board_idx);
273024dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
273124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
273220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
273331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Enable interrupts */
27346a59dcf8678cbc4106a8a6e158d7408a87691358Tejun Heo	if (msi && pci_enable_msi(pdev))
273531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pci_intx(pdev, 1);
273620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
273731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_pci_cfg(pdev, 0x68);
27384447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mv_print_info(host);
273920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27404447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	pci_set_master(pdev);
2741ea8b4db97aa41a66c05daa4055a1974692ccd52dJeff Garzik	pci_try_set_mwi(pdev);
27424447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
2743c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
274420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
274520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
274620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int __init mv_init(void)
274720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2748b7887196e38da54ff893897b80875d632d1a1114Pavel Roskin	return pci_register_driver(&mv_pci_driver);
274920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
275020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
275120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void __exit mv_exit(void)
275220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
275320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	pci_unregister_driver(&mv_pci_driver);
275420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
275520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
275620f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_AUTHOR("Brett Russ");
275720f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
275820f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_LICENSE("GPL");
275920f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DEVICE_TABLE(pci, mv_pci_tbl);
276020f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_VERSION(DRV_VERSION);
276120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2762ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikmodule_param(msi, int, 0444);
2763ddef9bb367b19383df627e388cb4c01c86ddba6cJeff GarzikMODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2764ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
276520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_init(mv_init);
276620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_exit(mv_exit);
2767