sata_mv.c revision 9af5c9c97dc9d599281778864c72b385f0c63341
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
167522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	PCI_IRQ_CAUSE_OFS		= 0x1d58,
168522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	PCI_IRQ_MASK_OFS		= 0x1d5c,
16920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
17020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
17120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
17220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
17320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_ERR		= (1 << 0),	/* shift by port # */
17420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_DONE		= (1 << 1),	/* shift by port # */
17520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
17620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
17720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_ERR			= (1 << 18),
17820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
17920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
180fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_0_3_COAL_DONE	= (1 << 8),
181fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_4_7_COAL_DONE	= (1 << 17),
18220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
18320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GPIO_INT		= (1 << 22),
18420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SELF_INT		= (1 << 23),
18520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TWSI_INT		= (1 << 24),
18620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
187fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
1888b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
18920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
19020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   HC_MAIN_RSVD),
191fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
192fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik				   HC_MAIN_RSVD_5),
19320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
19420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATAHC registers */
19520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_CFG_OFS		= 0,
19620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
19720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_CAUSE_OFS	= 0x14,
19831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
19920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
20020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	DEV_IRQ			= (1 << 8),	/* shift by port # */
20120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Shadow block registers */
20331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_BLK_OFS		= 0x100,
20431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
20520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
20620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATA registers */
20720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
20820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_ACTIVE_OFS		= 0x350,
20947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	PHY_MODE3		= 0x310,
210bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE4		= 0x314,
211bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE2		= 0x330,
212c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_MODE		= 0x74,
213c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_LT_MODE		= 0x30,
214c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_CTL		= 0x0C,
215bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	SATA_INTERFACE_CTL	= 0x050,
216bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
217bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_M2_PREAMP_MASK	= 0x7e0,
21820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Port registers */
22020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_CFG_OFS		= 0,
22131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
22231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ		= (1 << 5),
22331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
22431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
22531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
22620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
22720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
22820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
2296c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
2306c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
2316c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV		= (1 << 2),	/* device error */
2326c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
2336c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
2346c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
235c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
236c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
2376c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
238c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
2396c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
2406c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
2416c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
2426c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
2436c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
24420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
2456c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
2466c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
2476c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
2486c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
249c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_OVERRUN_5	= (1 << 5),
250c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_UNDERRUN_5	= (1 << 6),
251bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
252bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
253bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
254bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
255bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SERR |
256bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS |
2576c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
258bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
259bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
260bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY |
261bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_CTRL_RX_2 |
262bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_RX |
263bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_TX |
264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_TRANS_PROTO,
265bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE_5	= EDMA_ERR_D_PAR |
266bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
267bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
268bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_OVERRUN_5 |
270bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_UNDERRUN_5 |
271bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS_5 |
2726c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
273bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
274bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY,
27620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
27831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
27931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
28031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
28131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_PTR_SHIFT	= 5,
28231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
28331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
28431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
28531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
28631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_PTR_SHIFT	= 3,
28731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2880ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
2890ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_EN			= (1 << 0),	/* enable EDMA */
2900ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
2910ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
29220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
293c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	EDMA_IORDY_TMOUT	= 0x34,
294bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	EDMA_ARB_CFG		= 0x38,
295bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
29631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Host private flags (hp_flags) */
29731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_HP_FLAG_MSI		= (1 << 0),
29847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB0	= (1 << 1),
29947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB2	= (1 << 2),
30047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1B2	= (1 << 3),
30147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1C0	= (1 << 4),
302e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	MV_HP_ERRATA_XX42A0	= (1 << 5),
3030ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
3040ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
3050ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
30620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
30731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Port private flags (pp_flags) */
3080ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
3090ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
31020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
31120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
312ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
313ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
314e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
315bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
316095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzikenum {
317baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	/* DMA boundary 0xffff is required by the s/g splitting
318baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 * we need on /length/ in mv_fill-sg().
319baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 */
320baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	MV_DMA_BOUNDARY		= 0xffffU,
321095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3220ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* mask of register bits containing lower 32 bits
3230ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 * of EDMA request queue DMA address
3240ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 */
325095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
326095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3270ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* ditto, for response queue */
328095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
329095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik};
330095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
331522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikenum chip_type {
332522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_504x,
333522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_508x,
334522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_5080,
335522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_604x,
336522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_608x,
337e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_6042,
338e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_7042,
339522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik};
340522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
34131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ReQuest Block: 32B */
34231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crqb {
343e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr;
344e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr_hi;
345e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ctrl_flags;
346e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ata_cmd[11];
34731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
34820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
349e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstruct mv_crqb_iie {
350e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
351e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
352e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags;
353e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			len;
354e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			ata_cmd[4];
355e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
356e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
35731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ResPonse Block: 8B */
35831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crpb {
359e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			id;
360e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			flags;
361e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			tmstmp;
36220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
36320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
36431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
36531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_sg {
366e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
367e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags_size;
368e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
369e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			reserved;
37031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
37120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
37231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_port_priv {
37331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crqb		*crqb;
37431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crqb_dma;
37531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crpb		*crpb;
37631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crpb_dma;
37731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_sg		*sg_tbl;
37831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		sg_tbl_dma;
379bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
380bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		req_idx;
381bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		resp_idx;
382bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
38331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			pp_flags;
38431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
38531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
386bca1c4eb9411533d613123618c0d127fae532595Jeff Garzikstruct mv_port_signal {
387bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			amps;
388bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			pre;
389bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik};
390bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
39147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_host_priv;
39247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_hw_ops {
3932a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
3942a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
39547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
39647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
39747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
398c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
399c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
400522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
401522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
40247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
40347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
40431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_host_priv {
40531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			hp_flags;
406bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	struct mv_port_signal	signal[8];
40747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	const struct mv_hw_ops	*ops;
40820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
40920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
41020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void mv_irq_clear(struct ata_port *ap);
411da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
412da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
413da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
414da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
41531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap);
41631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap);
41731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc);
418e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc);
4199a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
420bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap);
421bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc);
422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap);
423bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap);
4246c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzikstatic int mv_slave_config(struct scsi_device *sdev);
42520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
42620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
4272a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4282a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
42947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
43047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
43147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
432c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
433c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
434522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
435522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
43647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
4372a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4382a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
43947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
44047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
44147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
442c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
443c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
444522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
445522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
446c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
447c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no);
44847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
449c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv5_sht = {
450c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.module			= THIS_MODULE,
451c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.name			= DRV_NAME,
452c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.ioctl			= ata_scsi_ioctl,
453c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.queuecommand		= ata_scsi_queuecmd,
454c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
455c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.this_id		= ATA_SHT_THIS_ID,
456baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
457c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
458c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.emulated		= ATA_SHT_EMULATED,
459c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.use_clustering		= 1,
460c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.proc_name		= DRV_NAME,
461c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.dma_boundary		= MV_DMA_BOUNDARY,
4626c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	.slave_configure	= mv_slave_config,
463c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.slave_destroy		= ata_scsi_slave_destroy,
464c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.bios_param		= ata_std_bios_param,
465c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik};
466c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
467c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv6_sht = {
46820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.module			= THIS_MODULE,
46920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
47020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.ioctl			= ata_scsi_ioctl,
47120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.queuecommand		= ata_scsi_queuecmd,
472c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.can_queue		= ATA_DEF_QUEUE,
47320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.this_id		= ATA_SHT_THIS_ID,
474baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
47520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
47620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.emulated		= ATA_SHT_EMULATED,
477d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	.use_clustering		= 1,
47820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.proc_name		= DRV_NAME,
47920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dma_boundary		= MV_DMA_BOUNDARY,
4806c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	.slave_configure	= mv_slave_config,
481ccf68c3405fca11386004674377d951b9b18e756Tejun Heo	.slave_destroy		= ata_scsi_slave_destroy,
48220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.bios_param		= ata_std_bios_param,
48320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
48420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
485c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv5_ops = {
486c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_disable		= ata_port_disable,
487c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
488c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_load		= ata_tf_load,
489c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_read		= ata_tf_read,
490c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.check_status		= ata_check_status,
491c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.exec_command		= ata_exec_command,
492c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.dev_select		= ata_std_dev_select,
493c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
494cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
495c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
496c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_prep		= mv_qc_prep,
497c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_issue		= mv_qc_issue,
4980d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
499c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
500c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.irq_clear		= mv_irq_clear,
501246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
502246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
503c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
506bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
509c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_read		= mv5_scr_read,
510c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_write		= mv5_scr_write,
511c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
512c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_start		= mv_port_start,
513c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_stop		= mv_port_stop,
514c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik};
515c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
516c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv6_ops = {
51720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.port_disable		= ata_port_disable,
51820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
51920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_load		= ata_tf_load,
52020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_read		= ata_tf_read,
52120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.check_status		= ata_check_status,
52220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.exec_command		= ata_exec_command,
52320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dev_select		= ata_std_dev_select,
52420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
525cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
52620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
52731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_prep		= mv_qc_prep,
52831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_issue		= mv_qc_issue,
5290d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
53020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
53120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.irq_clear		= mv_irq_clear,
532246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
533246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
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	.port_disable		= ata_port_disable,
549e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
550e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_load		= ata_tf_load,
551e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_read		= ata_tf_read,
552e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.check_status		= ata_check_status,
553e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.exec_command		= ata_exec_command,
554e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.dev_select		= ata_std_dev_select,
555e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
556cffacd85bcf6fc652292001873119333555fe260Jeff Garzik	.cable_detect		= ata_cable_sata,
557e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
558e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_prep		= mv_qc_prep_iie,
559e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_issue		= mv_qc_issue,
5600d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
561e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
562e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.irq_clear		= mv_irq_clear,
563246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
564246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_ack		= ata_irq_ack,
565e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
566bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
567bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.post_internal_cmd	= mv_post_int_cmd,
568bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
569bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
570bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
571e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_read		= mv_scr_read,
572e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_write		= mv_scr_write,
573e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
574e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_start		= mv_port_start,
575e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_stop		= mv_port_stop,
576e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
577e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
57898ac62defe529d04a192688f40d801a2d8fbcf98Arjan van de Venstatic const struct ata_port_info mv_port_info[] = {
57920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_504x */
580cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= MV_COMMON_FLAGS,
58131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
582bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
583c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
58420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
58520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_508x */
586c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
58731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
588bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
589c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
59020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
59147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	{  /* chip_5080 */
592c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
59347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
594bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
595c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
59647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	},
59720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_604x */
598c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
59931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
600bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
601c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
60220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
60320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_608x */
604c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
605c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				  MV_FLAG_DUAL_HC,
60631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
607bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
608c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
60920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
610e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_6042 */
611c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
612e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
613bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
614e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
615e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
616e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_7042 */
617c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
618e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
619bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
620e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
621e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
62220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
62320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
6243b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id mv_pci_tbl[] = {
6252d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
6262d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
6272d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
6282d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
629cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	/* RocketRAID 1740/174x have different identifiers */
630cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
631cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
6322d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6332d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
6342d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
6352d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
6362d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
6372d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
6382d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6392d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
6402d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
641d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	/* Adaptec 1430SA */
642d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
643d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger
644e93f09dc2d49d8e98818a93ad17f3ede91533738Olof Johansson	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
645e93f09dc2d49d8e98818a93ad17f3ede91533738Olof Johansson
6466a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	/* add Marvell 7042 support */
6476a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
6486a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom
6492d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ }			/* terminate list */
65020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
65120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
65220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic struct pci_driver mv_pci_driver = {
65320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.name			= DRV_NAME,
65420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.id_table		= mv_pci_tbl,
65520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.probe			= mv_init_one,
65620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.remove			= ata_pci_remove_one,
65720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
65820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
65947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv5xxx_ops = {
66047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv5_phy_errata,
66147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv5_enable_leds,
66247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv5_read_preamp,
66347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv5_reset_hc,
664522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv5_reset_flash,
665522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv5_reset_bus,
66647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
66747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
66847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv6xxx_ops = {
66947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv6_phy_errata,
67047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv6_enable_leds,
67147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv6_read_preamp,
67247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv6_reset_hc,
673522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv6_reset_flash,
674522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv_reset_pci_bus,
67547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
67647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
67720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ/*
678ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik * module options
679ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik */
680ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikstatic int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
681ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
682ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
683d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik/* move to PCI layer or libata core? */
684d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzikstatic int pci_go_64(struct pci_dev *pdev)
685d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik{
686d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	int rc;
687d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
688d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
689d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
690d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
691d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
692d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			if (rc) {
693d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				dev_printk(KERN_ERR, &pdev->dev,
694d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik					   "64-bit DMA enable failed\n");
695d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				return rc;
696d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			}
697d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
698d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	} else {
699d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
700d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
701d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
702d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit DMA enable failed\n");
703d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
704d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
705d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
706d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		if (rc) {
707d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
708d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik				   "32-bit consistent DMA enable failed\n");
709d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik			return rc;
710d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		}
711d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	}
712d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
713d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	return rc;
714d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik}
715d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
716ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik/*
71720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Functions
71820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ */
71920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
72020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void writelfl(unsigned long data, void __iomem *addr)
72120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writel(data, addr);
72320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	(void) readl(addr);	/* flush to avoid PCI posted write */
72420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
72520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
72620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
72720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
72920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
73020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
731c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hc_from_port(unsigned int port)
732c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
733c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port >> MV_PORT_HC_SHIFT;
734c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
735c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
736c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hardport_from_port(unsigned int port)
737c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
738c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port & MV_PORT_MASK;
739c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
740c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
741c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline void __iomem *mv_hc_base_from_port(void __iomem *base,
742c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik						 unsigned int port)
743c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
744c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return mv_hc_base(base, mv_hc_from_port(port));
745c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
746c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
74720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
74820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
749c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return  mv_hc_base_from_port(base, port) +
7508b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		MV_SATAHC_ARBTR_REG_SZ +
751c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
75220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
75420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_ap_base(struct ata_port *ap)
75520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
7560d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
75720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
759cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic inline int mv_get_hc_count(unsigned long port_flags)
76031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
761cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
76231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
76331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
76431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_irq_clear(struct ata_port *ap)
76520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
76620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
76720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
7686c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzikstatic int mv_slave_config(struct scsi_device *sdev)
7696c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik{
7706c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	int rc = ata_scsi_slave_config(sdev);
7716c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	if (rc)
7726c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik		return rc;
7736c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik
7746c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	blk_queue_max_phys_segments(sdev->request_queue, MV_MAX_SG_CT / 2);
7756c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik
7766c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik	return 0;	/* scsi layer doesn't check return value, sigh */
7776c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik}
7786c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik
779c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_set_edma_ptrs(void __iomem *port_mmio,
780c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_host_priv *hpriv,
781c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_port_priv *pp)
782c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik{
783bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 index;
784bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
785c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
786c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize request queue
787c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
788bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
789bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
790c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crqb_dma & 0x3ff);
791c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
792bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
793c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
794c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
795c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
796bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crqb_dma & 0xffffffff) | index,
797c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
798c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
799bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
800c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
801c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
802c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize response queue
803c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
804bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
805bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
806c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crpb_dma & 0xff);
807c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
808c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
809c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
810bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & 0xffffffff) | index,
811c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
812c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
813bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
814c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
815bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
816c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
817c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik}
818c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
81905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
82005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_start_dma - Enable eDMA engine
82105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @base: port base address
82205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pp: port private data
82305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
824beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
825beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
82605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
82705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
82805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
82905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
830c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
831c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 struct mv_port_priv *pp)
83220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
833c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
834bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* clear EDMA event indicators, if any */
835bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
836bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
837bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_set_edma_ptrs(base, hpriv, pp);
838bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
839afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
840afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
841afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
842beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
84320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
84420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
84505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
8460ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik *      __mv_stop_dma - Disable eDMA engine
84705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
84805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
849beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
850beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
85105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
85205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
85305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
85405b308e1df6d9d673daedb517969241f41278b52Brett Russ */
8550ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int __mv_stop_dma(struct ata_port *ap)
85620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
85731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
85831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp	= ap->private_data;
85931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 reg;
860c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int i, err = 0;
86131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
8624537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
863afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		/* Disable EDMA if active.   The disable bit auto clears.
86431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
86531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
86631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
867afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	} else {
868beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
869afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ  	}
8708b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
87131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* now properly wait for the eDMA to stop */
87231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (i = 1000; i > 0; i--) {
87331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		reg = readl(port_mmio + EDMA_CMD_OFS);
8744537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		if (!(reg & EDMA_EN))
87531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
8764537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik
87731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		udelay(100);
87831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
87931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
880c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (reg & EDMA_EN) {
881f15a1dafed22d5037e0feea7528e1eeb28a1a7a3Tejun Heo		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
882c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		err = -EIO;
88331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
884c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
885c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	return err;
88620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
88720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8880ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int mv_stop_dma(struct ata_port *ap)
8890ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik{
8900ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
8910ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	int rc;
8920ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8930ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
8940ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	rc = __mv_stop_dma(ap);
8950ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
8960ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
8970ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	return rc;
8980ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik}
8990ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
9008a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#ifdef ATA_DEBUG
90131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_mem(void __iomem *start, unsigned bytes)
90220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
90331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
90431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
90531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%p: ", start + b);
90631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
90731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			printk("%08x ",readl(start + b));
90831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
90931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
91031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
91131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
91231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
9138a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#endif
9148a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik
91531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
91631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
91731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
91831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
91931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 dw;
92031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
92131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%02x: ", b);
92231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
92331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			(void) pci_read_config_dword(pdev,b,&dw);
92431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			printk("%08x ",dw);
92531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
92631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
92731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
92831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
92931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
93031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
93131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_all_regs(void __iomem *mmio_base, int port,
93231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			     struct pci_dev *pdev)
93331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
93431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
9358b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	void __iomem *hc_base = mv_hc_base(mmio_base,
93631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ					   port >> MV_PORT_HC_SHIFT);
93731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_base;
93831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int start_port, num_ports, p, start_hc, num_hcs, hc;
93931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
94031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (0 > port) {
94131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = start_port = 0;
94231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = 8;		/* shld be benign for 4 port devs */
94331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_hcs = 2;
94431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	} else {
94531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = port >> MV_PORT_HC_SHIFT;
94631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_port = port;
94731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = num_hcs = 1;
94831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
9498b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
95031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports > 1 ? num_ports - 1 : start_port);
95131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
95231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (NULL != pdev) {
95331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("PCI config space regs:\n");
95431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_pci_cfg(pdev, 0x68);
95531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
95631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	DPRINTK("PCI regs:\n");
95731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xc00, 0x3c);
95831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xd00, 0x34);
95931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xf00, 0x4);
96031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0x1d00, 0x6c);
96131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
962d220c37e0a3c9a47ae00e87e044d963b3ea040bcDan Aloni		hc_base = mv_hc_base(mmio_base, hc);
96331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("HC regs (HC %i):\n", hc);
96431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(hc_base, 0x1c);
96531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
96631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (p = start_port; p < start_port + num_ports; p++) {
96731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port_base = mv_port_base(mmio_base, p);
96831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("EDMA regs (port %i):\n",p);
96931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base, 0x54);
97031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("SATA regs (port %i):\n",p);
97131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base+0x300, 0x60);
97231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
97331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
97420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
97520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
97620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic unsigned int mv_scr_offset(unsigned int sc_reg_in)
97720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
97820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs;
97920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
98020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	switch (sc_reg_in) {
98120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_STATUS:
98220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_CONTROL:
98320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ERROR:
98420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
98520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
98620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ACTIVE:
98720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
98820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
98920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	default:
99020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = 0xffffffffU;
99120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
99220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
99320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return ofs;
99420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
99520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
996da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
99720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
99820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
99920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1000da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1001da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(mv_ap_base(ap) + ofs);
1002da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1003da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1004da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
100520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
100620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1007da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
100820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
100920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
101020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1011da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
101220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		writelfl(val, mv_ap_base(ap) + ofs);
1013da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1014da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1015da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
101620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
101720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1018c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
1019c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			void __iomem *port_mmio)
1020e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1021e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
1022e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1023e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* set up non-NCQ EDMA configuration */
1024c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	cfg &= ~(1 << 9);	/* disable eQue */
1025e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1026e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	if (IS_GEN_I(hpriv)) {
1027e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1028e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 8);	/* enab config burst size mask */
1029e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1030e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1031e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	else if (IS_GEN_II(hpriv)) {
1032e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~0x1f;		/* clear queue depth */
1033e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
1034e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
1035e728eabea110da90e69c05855e3a11174edb77efJeff Garzik	}
1036e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1037e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	else if (IS_GEN_IIE(hpriv)) {
1038e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
1039e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
1040e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
1041e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 18);	/* enab early completion */
1042e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
1043e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
10444537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		cfg &= ~(EDMA_CFG_NCQ);	/* clear NCQ */
1045e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
1046e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1047e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
1048e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1049e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
105005b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
105105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_start - Port specific init/start routine.
105205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
105305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
105405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Allocate and point to DMA memory, init port private memory,
105505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      zero indices.
105605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
105705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
105805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
105905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
106031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap)
106131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1062cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct device *dev = ap->host->dev;
1063cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
106431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp;
106531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
106631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void *mem;
106731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t mem_dma;
10680ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
106924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	int rc;
107031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
107124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
10726037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!pp)
107324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
107431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
107524dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
107624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo				  GFP_KERNEL);
10776037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!mem)
107824dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
107931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
108031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10816037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	rc = ata_pad_alloc(ap, dev);
10826037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (rc)
108324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
10846037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik
10858b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* First item in chunk of DMA memory:
108631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command request table (CRQB), 32 bytes each in size
108731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
108831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb = mem;
108931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crqb_dma = mem_dma;
109031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRQB_Q_SZ;
109131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRQB_Q_SZ;
109231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
10938b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* Second item:
109431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * 32-slot command response table (CRPB), 8 bytes each in size
109531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
109631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb = mem;
109731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->crpb_dma = mem_dma;
109831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem += MV_CRPB_Q_SZ;
109931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mem_dma += MV_CRPB_Q_SZ;
110031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
110131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Third item:
110231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
110331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
110431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl = mem;
110531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pp->sg_tbl_dma = mem_dma;
110631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11070ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
11080ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
1109c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_edma_cfg(ap, hpriv, port_mmio);
1110e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1111c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_set_edma_ptrs(port_mmio, hpriv, pp);
111231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11130ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
11140ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
111531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Don't turn on EDMA here...do it before DMA commands only.  Else
111631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * we'll be unable to send non-data, PIO, etc due to restricted access
111731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * to shadow regs.
111831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
111931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	ap->private_data = pp;
112031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
112131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
112231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
112305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
112405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_stop - Port specific cleanup/stop routine.
112505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
112605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
112705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Stop DMA, cleanup port memory.
112805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
112905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
1130cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine uses the host lock to protect the DMA stop.
113105b308e1df6d9d673daedb517969241f41278b52Brett Russ */
113231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap)
113331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
113431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_stop_dma(ap);
113531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
113631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
113705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
113805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
113905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command whose SG list to source from
114005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
114105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Populate the SG list and mark the last entry.
114205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
114305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
114405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
114505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
11466c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzikstatic void mv_fill_sg(struct ata_queued_cmd *qc)
114731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
114831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = qc->ap->private_data;
1149972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	struct scatterlist *sg;
1150d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	struct mv_sg *mv_sg;
115131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1152d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	mv_sg = pp->sg_tbl;
1153972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	ata_for_each_sg(sg, qc) {
1154d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		dma_addr_t addr = sg_dma_address(sg);
1155d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		u32 sg_len = sg_dma_len(sg);
115622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
11574007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		while (sg_len) {
11584007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 offset = addr & 0xffff;
11594007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 len = sg_len;
116022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
11614007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			if ((offset + sg_len > 0x10000))
11624007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson				len = 0x10000 - offset;
11634007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11644007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
11654007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
11666c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik			mv_sg->flags_size = cpu_to_le32(len & 0xffff);
11674007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11684007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			sg_len -= len;
11694007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			addr += len;
11704007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11714007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			if (!sg_len && ata_sg_is_last(sg, qc))
11724007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson				mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
11734007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
11744007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg++;
11754007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		}
117622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
117731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
117831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
117931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1180e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lordstatic inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
118131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1182559eedad7f7764dacca33980127b4615011230e4Mark Lord	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
118331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		(last ? CRQB_CMD_LAST : 0);
1184559eedad7f7764dacca33980127b4615011230e4Mark Lord	*cmdw = cpu_to_le16(tmp);
118531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
118631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
118705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
118805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_prep - Host specific command preparation.
118905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to prepare
119005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
119105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
119205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it handles prep of the CRQB
119305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      (command request block), does some sanity checking, and calls
119405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the SG load routine.
119505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
119605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
119705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
119805b308e1df6d9d673daedb517969241f41278b52Brett Russ */
119931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc)
120031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
120131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_port *ap = qc->ap;
120231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = ap->private_data;
1203e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16 *cw;
120431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_taskfile *tf;
120531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u16 flags = 0;
1206a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
120731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1208c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik 	if (qc->tf.protocol != ATA_PROT_DMA)
120931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
121020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
121131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Fill in command request block
121231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
1213e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
121431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		flags |= CRQB_FLAG_READ;
1215beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
121631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	flags |= qc->tag << CRQB_TAG_SHIFT;
12174537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* 50xx appears to ignore this*/
121831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1219bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1220bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1221a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1222a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr =
122331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1224a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr_hi =
122531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1226a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
122731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1228a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	cw = &pp->crqb[in_index].ata_cmd[0];
122931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	tf = &qc->tf;
123031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
123131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Sadly, the CRQB cannot accomodate all registers--there are
123231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * only 11 bytes...so we must pick and choose required
123331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * registers based on the command.  So, we drop feature and
123431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * hob_feature for [RW] DMA commands, but they are needed for
123531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * NCQ.  NCQ will drop hob_nsect.
123620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
123731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	switch (tf->command) {
123831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ:
123931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ_EXT:
124031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE:
124131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE_EXT:
1242c15d85c8f3f73b5f20aae7928e25b6996f16b328Jens Axboe	case ATA_CMD_WRITE_FUA_EXT:
124331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
124431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
124531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
124631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_READ:
124731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_WRITE:
12488b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
124931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
125031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
125131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif				/* FIXME: remove this line when NCQ added */
125231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	default:
125331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* The only other commands EDMA supports in non-queued and
125431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
125531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * of which are defined/used by Linux.  If we get here, this
125631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * driver needs work.
125731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 *
125831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * FIXME: modify libata to give qc_prep a return value and
125931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * return error here.
126031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
126131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		BUG_ON(tf->command);
126231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
126331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
126431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
126531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
126631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
126731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
126831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
126931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
127031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
127131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
127231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
127331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1274e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1275e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1276e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	mv_fill_sg(qc);
1277e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1278e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1279e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik/**
1280e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      mv_qc_prep_iie - Host specific command preparation.
1281e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      @qc: queued command to prepare
1282e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1283e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      This routine simply redirects to the general purpose routine
1284e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      if command is not DMA.  Else, it handles prep of the CRQB
1285e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      (command request block), does some sanity checking, and calls
1286e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      the SG load routine.
1287e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1288e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      LOCKING:
1289e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      Inherited from caller.
1290e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik */
1291e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1292e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1293e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_port *ap = qc->ap;
1294e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_port_priv *pp = ap->private_data;
1295e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_crqb_iie *crqb;
1296e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_taskfile *tf;
1297a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
1298e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 flags = 0;
1299e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1300c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik 	if (qc->tf.protocol != ATA_PROT_DMA)
1301e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1302e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1303e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* Fill in Gen IIE command request block
1304e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	 */
1305e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1306e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		flags |= CRQB_FLAG_READ;
1307e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1308beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1309e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	flags |= qc->tag << CRQB_TAG_SHIFT;
1310bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	flags |= qc->tag << CRQB_IOID_SHIFT;	/* "I/O Id" is -really-
13114537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik						   what we use as our tag */
1312e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1313bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1314bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1315a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1316a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1317e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1318e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1319e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->flags = cpu_to_le32(flags);
1320e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1321e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	tf = &qc->tf;
1322e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[0] = cpu_to_le32(
1323e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->command << 16) |
1324e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->feature << 24)
1325e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1326e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[1] = cpu_to_le32(
1327e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbal << 0) |
1328e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbam << 8) |
1329e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbah << 16) |
1330e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->device << 24)
1331e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1332e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[2] = cpu_to_le32(
1333e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbal << 0) |
1334e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbam << 8) |
1335e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbah << 16) |
1336e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_feature << 24)
1337e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1338e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[3] = cpu_to_le32(
1339e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->nsect << 0) |
1340e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_nsect << 8)
1341e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1342e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1343e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
134431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
134531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_fill_sg(qc);
134631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
134731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
134805b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
134905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_issue - Initiate a command to the host
135005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to start
135105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
135205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
135305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it sanity checks our local
135405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      caches of the request producer/consumer indices then enables
135505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      DMA and bumps the request producer index.
135605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
135705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
135805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
135905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
13609a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
136131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1362c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct ata_port *ap = qc->ap;
1363c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1364c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1365c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1366bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 in_index;
136731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1368c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (qc->tf.protocol != ATA_PROT_DMA) {
136931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* We're about to send a non-EDMA capable command to the
137031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * port.  Turn off EDMA so there won't be problems accessing
137131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * shadow block, etc registers.
137231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
13730ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		__mv_stop_dma(ap);
137431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return ata_qc_issue_prot(qc);
137531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
137631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1377bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_start_dma(port_mmio, hpriv, pp);
1378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1379bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
138031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
138131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* until we do queuing, the queue should be empty at this point */
1382a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1383a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
138431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1385bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	pp->req_idx++;
138631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1387bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
138831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
138931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and write the request in pointer to kick the EDMA to life */
1390bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
1391bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
139231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
139331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
139431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
139531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
139605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
139705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_err_intr - Handle error interrupts on the port
139805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
13999b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord *      @reset_allowed: bool: 0 == don't trigger from reset here
140005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
140105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      In most cases, just clear the interrupt and move on.  However,
140205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      some cases require an eDMA reset, which is done right before
140305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the COMRESET in mv_phy_reset().  The SERR case requires a
140405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      clear of pending errors in the SATA SERROR register.  Finally,
140505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if the port disabled DMA, update our cached copy to match.
140605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
140705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
140805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
140905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1410bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
141131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
141231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
1413bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 edma_err_cause, eh_freeze_mask, serr = 0;
1414bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1415bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1416bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
1417bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int action = 0, err_mask = 0;
14189af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_eh_info *ehi = &ap->link.eh_info;
141920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1420bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_clear_desc(ehi);
142120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!edma_enabled) {
1423bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* just a guess: do we need to do this? should we
1424bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * expand this, and do it in all cases?
1425bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
142681952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_read(ap, SCR_ERROR, &serr);
142781952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_write_flush(ap, SCR_ERROR, serr);
142820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1429bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1430bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1431bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1432bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
1433bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1434bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/*
1435bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * all generations share these EDMA error cause bits
1436bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
1437bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1438bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & EDMA_ERR_DEV)
1439bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_DEV;
1440bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
14416c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
1442bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			EDMA_ERR_INTRL_PAR)) {
1443bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_ATA_BUS;
1444bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1445b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo		ata_ehi_push_desc(ehi, "parity error");
1446bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1447bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
1448bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_hotplugged(ehi);
1449bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
1450b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			"dev disconnect" : "dev connect");
1451bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1452bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1453ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv)) {
1454bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE_5;
1455bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1456bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
1457bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1458bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1459b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1460bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1461bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	} else {
1462bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE;
1463bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1464bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
1465bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct mv_port_priv *pp	= ap->private_data;
1466bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1467b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1468bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1469bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1470bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SERR) {
1471bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			sata_scr_read(ap, SCR_ERROR, &serr);
1472bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			sata_scr_write_flush(ap, SCR_ERROR, serr);
1473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_ATA_BUS;
1474bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			action |= ATA_EH_HARDRESET;
1475bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1476afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
147720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
147820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Clear EDMA now that SERR cleanup done */
147920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
148020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1481bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!err_mask) {
1482bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask = AC_ERR_OTHER;
1483bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		action |= ATA_EH_HARDRESET;
1484bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1485bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1486bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->serror |= serr;
1487bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->action |= action;
1488bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1489bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc)
1490bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		qc->err_mask |= err_mask;
1491bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1492bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehi->err_mask |= err_mask;
1493bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1494bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & eh_freeze_mask)
1495bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_freeze(ap);
1496bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1497bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_abort(ap);
1498bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1499bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_pio(struct ata_port *ap)
1501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1502bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u8 ata_status;
1504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* ignore spurious intr if drive still BUSY */
1506bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_status = readb(ap->ioaddr.status_addr);
1507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(ata_status & ATA_BUSY))
1508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1510bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get active ATA command */
15119af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	qc = ata_qc_from_tag(ap, ap->link.active_tag);
1512bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(!qc))			/* no active tag */
1513bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1514bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc->tf.flags & ATA_TFLAG_POLLING)	/* polling; we don't own qc */
1515bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1516bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1517bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* and finally, complete the ATA command */
1518bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	qc->err_mask |= ac_err_mask(ata_status);
1519bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_qc_complete(qc);
1520bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1521bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1522bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_edma(struct ata_port *ap)
1523bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1524bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1525bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1526bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1527bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1528bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 out_index, in_index;
1529bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	bool work_done = false;
1530bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1531bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get h/w response queue pointer */
1532bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1533bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1534bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1535bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	while (1) {
1536bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		u16 status;
15376c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		unsigned int tag;
1538bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1539bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* get s/w response queue last-read pointer, and compare */
1540bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
1541bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (in_index == out_index)
1542bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
1543bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1544bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* 50xx: get active ATA command */
15450ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		if (IS_GEN_I(hpriv))
15469af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			tag = ap->link.active_tag;
1547bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15486c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		/* Gen II/IIE: get active ATA command via tag, to enable
15496c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * support for queueing.  this works transparently for
15506c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * queued and non-queued modes.
1551bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
15526c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else if (IS_GEN_II(hpriv))
15536c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15546c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_6) & 0x3f;
1555bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15566c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		else /* IS_GEN_IIE */
15576c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			tag = (le16_to_cpu(pp->crpb[out_index].id)
15586c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				>> CRPB_IOID_SHIFT_7) & 0x3f;
1559bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15606c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		qc = ata_qc_from_tag(ap, tag);
1561bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1562bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
1563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * bits (WARNING: might not necessarily be associated
1564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * with this command), which -should- be clear
1565bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * if all is well
1566bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1567bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		status = le16_to_cpu(pp->crpb[out_index].flags);
1568bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(status & 0xff)) {
1569bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1570bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			return;
1571bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1572bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1573bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* and finally, complete the ATA command */
1574bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (qc) {
1575bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			qc->err_mask |=
1576bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
1577bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_qc_complete(qc);
1578bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1579bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15800ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		/* advance software response queue pointer, to
1581bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * indicate (after the loop completes) to hardware
1582bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * that we have consumed a response queue entry.
1583bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1584bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		work_done = true;
1585bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->resp_idx++;
1586bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1587bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1588bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (work_done)
1589bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
1590bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 (out_index << EDMA_RSP_Q_PTR_SHIFT),
1591bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
159220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
159320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
159405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
159505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_host_intr - Handle all interrupts on the given host controller
1596cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      @host: host specific structure
159705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @relevant: port error bits relevant to this host controller
159805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @hc: which host controller we're to look at
159905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
160005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read then write clear the HC interrupt status then walk each
160105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port connected to the HC and see if it needs servicing.  Port
160205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      success ints are reported in the HC interrupt status reg, the
160305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port error ints are reported in the higher level main
160405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt status register and thus are passed in via the
160505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      'relevant' argument.
160605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
160705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
160805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
160905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1610cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
161120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
16120d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
161320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
161420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 hc_irq_cause;
1615c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int port, port0;
161620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1617351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (hc == 0)
161820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = 0;
1619351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	else
162020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = MV_PORTS_PER_HC;
162120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
162220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* we'll need the HC success int register in most cases */
162320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
1624bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!hc_irq_cause)
1625bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1626bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1627bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
162820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
162920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
163020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		hc,relevant,hc_irq_cause);
163120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
163220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
1633cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		struct ata_port *ap = host->ports[port];
163463af2a5c5990d95f1e7d8795f1425fb976ea2b4bMark Lord		struct mv_port_priv *pp = ap->private_data;
1635bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		int have_err_bits, hard_port, shift;
163655d8ca4f8094246da6e71889a4e04bfafaa78b10Jeff Garzik
1637bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
1638a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik			continue;
1639a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik
164031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		shift = port << 1;		/* (port * 2) */
164120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (port >= MV_PORTS_PER_HC) {
164220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ			shift++;	/* skip bit 8 in the HC Main IRQ reg */
164320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
1644bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		have_err_bits = ((PORT0_ERR << shift) & relevant);
1645bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1646bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(have_err_bits)) {
1647bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct ata_queued_cmd *qc;
16488b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
16499af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1650bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
1651bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				continue;
1652bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1653bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1654bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			continue;
1655bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1656bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1657bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1658bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1659bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1660bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
1661bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_edma(ap);
1662bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		} else {
1663bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((DEV_IRQ << hard_port) & hc_irq_cause)
1664bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_pio(ap);
166520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
166620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
166720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("EXIT\n");
166820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
166920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1670bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_pci_error(struct ata_host *host, void __iomem *mmio)
1671bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1672bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_port *ap;
1673bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1674bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_info *ehi;
1675bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int i, err_mask, printed = 0;
1676bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 err_cause;
1677bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1678bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS);
1679bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1680bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
1681bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		   err_cause);
1682bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1683bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	DPRINTK("All regs @ PCI error\n");
1684bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1685bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1686bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
1687bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1688bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	for (i = 0; i < host->n_ports; i++) {
1689bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ap = host->ports[i];
1690bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (!ata_port_offline(ap)) {
16919af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			ehi = &ap->link.eh_info;
1692bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_ehi_clear_desc(ehi);
1693bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (!printed++)
1694bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ata_ehi_push_desc(ehi,
1695bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik					"PCI err cause 0x%08x", err_cause);
1696bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_HOST_BUS;
1697bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ehi->action = ATA_EH_HARDRESET;
16989af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1699bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc)
1700bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				qc->err_mask |= err_mask;
1701bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			else
1702bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ehi->err_mask |= err_mask;
1703bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1704bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_port_freeze(ap);
1705bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1706bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1707bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1708bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
170905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
1710c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik *      mv_interrupt - Main interrupt event handler
171105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @irq: unused
171205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @dev_instance: private data; in this case the host structure
171305b308e1df6d9d673daedb517969241f41278b52Brett Russ *
171405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read the read only register to determine if any host
171505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      controllers have pending interrupts.  If so, call lower level
171605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      routine to handle.  Also check for PCI errors which are only
171705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      reported here.
171805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
17198b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik *      LOCKING:
1720cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine holds the host lock while processing pending
172105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts.
172205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
17237d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mv_interrupt(int irq, void *dev_instance)
172420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
1725cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
172620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int hc, handled = 0, n_hcs;
17270d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
172820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 irq_stat;
172920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
173020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
173120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
173220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* check the cases where we either have nothing pending or have read
173320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 * a bogus register value which can indicate HW removal or PCI fault
173420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
1735351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (!irq_stat || (0xffffffffU == irq_stat))
173620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return IRQ_NONE;
173720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1738cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	n_hcs = mv_get_hc_count(host->ports[0]->flags);
1739cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_lock(&host->lock);
174020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1741bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(irq_stat & PCI_ERR)) {
1742bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_pci_error(host, mmio);
1743bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		handled = 1;
1744bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		goto out_unlock;	/* skip all other HC irq handling */
1745bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1746bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
174720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hcs; hc++) {
174820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
174920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (relevant) {
1750cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik			mv_host_intr(host, relevant, hc);
1751bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			handled = 1;
175220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
175320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1754615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
1755bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikout_unlock:
1756cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
175720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
175820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return IRQ_RETVAL(handled);
175920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
176020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1761c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1762c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1763c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1764c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1765c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1766c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return hc_mmio + ofs;
1767c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1768c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1769c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1770c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1771c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs;
1772c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1773c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	switch (sc_reg_in) {
1774c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_STATUS:
1775c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_ERROR:
1776c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_CONTROL:
1777c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = sc_reg_in * sizeof(u32);
1778c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1779c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	default:
1780c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = 0xffffffffU;
1781c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1782c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1783c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return ofs;
1784c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1785c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1786da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
1787c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
17880d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
17890d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1790c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1791c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1792da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1793da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(addr + ofs);
1794da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1795da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1796da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1797c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1798c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1799da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1800c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
18010d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
18020d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1803c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1804c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1805da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
18060d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writelfl(val, addr + ofs);
1807da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1808da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1809da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1810c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1811c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1812522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1813522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1814522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	int early_5080;
1815522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
181644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
1817522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1818522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	if (!early_5080) {
1819522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1820522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		tmp |= (1 << 0);
1821522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1822522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	}
1823522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1824522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	mv_reset_pci_bus(pdev, mmio);
1825522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1826522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1827522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1828522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1829522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1830522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1831522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
183247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1833ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
1834ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1835c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1836c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1837c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1838c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1839c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1840c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1841c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1842ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1843ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
184447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1845ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1846522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	u32 tmp;
1847522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1848522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0, mmio + MV_GPIO_PORT_CTL);
1849522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1850522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1851522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1852522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1853522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp |= ~(1 << 0);
1854522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1855ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1856ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
18572a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
18582a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
1859bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
1860c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1861c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1862c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1863c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1864c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1865c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	if (fix_apm_sq) {
1866c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_LT_MODE);
1867c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= (1 << 19);
1868c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_LT_MODE);
1869c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1870c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_PHY_CTL);
1871c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp &= ~0x3;
1872c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= 0x1;
1873c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_PHY_CTL);
1874c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1875c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1876c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1877c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= ~mask;
1878c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].pre;
1879c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].amps;
1880c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, phy_mmio + MV5_PHY_MODE);
1881bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
1882bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
1883c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1884c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1885c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, port_mmio + (reg))
1886c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1887c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port)
1888c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1889c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
1890c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1891c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1892c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1893c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	mv_channel_reset(hpriv, mmio, port);
1894c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1895c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x028);	/* command */
1896c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1897c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x004);	/* timer */
1898c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x008);	/* irq err cause */
1899c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);	/* irq err mask */
1900c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);	/* rq bah */
1901c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);	/* rq inp */
1902c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);	/* rq outp */
1903c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x01c);	/* respq bah */
1904c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x024);	/* respq outp */
1905c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x020);	/* respq inp */
1906c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x02c);	/* test control */
1907c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1908c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1909c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1910c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1911c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, hc_mmio + (reg))
1912c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1913c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int hc)
191447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik{
1915c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1916c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1917c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1918c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);
1919c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);
1920c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);
1921c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);
1922c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1923c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(hc_mmio + 0x20);
1924c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= 0x1c1c1c1c;
1925c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= 0x03030303;
1926c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, hc_mmio + 0x20);
1927c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1928c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1929c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1930c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1931c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1932c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1933c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int hc, port;
1934c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1935c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	for (hc = 0; hc < n_hc; hc++) {
1936c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		for (port = 0; port < MV_PORTS_PER_HC; port++)
1937c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			mv5_reset_hc_port(hpriv, mmio,
1938c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik					  (hc * MV_PORTS_PER_HC) + port);
1939c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1940c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mv5_reset_one_hc(hpriv, mmio, hc);
1941c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1942c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1943c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return 0;
194447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik}
194547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
1946101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1947101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#define ZERO(reg) writel(0, mmio + (reg))
1948101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1949101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1950101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1951101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1952101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_PCI_MODE);
1953101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0xff00ffff;
1954101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_PCI_MODE);
1955101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1956101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_DISC_TIMER);
1957101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_MSI_TRIGGER);
1958101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1959101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(HC_MAIN_IRQ_MASK_OFS);
1960101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_SERR_MASK);
1961101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(PCI_IRQ_CAUSE_OFS);
1962101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(PCI_IRQ_MASK_OFS);
1963101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_LOW_ADDRESS);
1964101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1965101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_ATTRIBUTE);
1966101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_COMMAND);
1967101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1968101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
1969101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1970101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1971101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1972101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
1973101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1974101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	mv5_reset_flash(hpriv, mmio);
1975101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1976101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_GPIO_PORT_CTL);
1977101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0x3;
1978101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp |= (1 << 5) | (1 << 6);
1979101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_GPIO_PORT_CTL);
1980101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
1981101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1982101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik/**
1983101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      mv6_reset_hc - Perform the 6xxx global soft reset
1984101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      @mmio: base address of the HBA
1985101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1986101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      This routine only applies to 6xxx parts.
1987101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
1988101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      LOCKING:
1989101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      Inherited from caller.
1990101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik */
1991c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1992c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1993101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
1994101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1995101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	int i, rc = 0;
1996101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 t;
1997101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
1998101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* Following procedure defined in PCI "main command and status
1999101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 * register" table.
2000101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 */
2001101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	t = readl(reg);
2002101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(t | STOP_PCI_MASTER, reg);
2003101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2004101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	for (i = 0; i < 1000; i++) {
2005101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2006101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2007101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		if (PCI_MASTER_EMPTY & t) {
2008101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik			break;
2009101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		}
2010101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2011101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(PCI_MASTER_EMPTY & t)) {
2012101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
2013101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2014101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2015101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2016101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2017101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* set reset */
2018101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2019101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2020101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t | GLOB_SFT_RST, reg);
2021101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2022101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2023101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
2024101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2025101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(GLOB_SFT_RST & t)) {
2026101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
2027101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2028101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2029101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2030101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2031101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
2032101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2033101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2034101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
2035101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2036101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2037101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while ((GLOB_SFT_RST & t) && (i-- > 0));
2038101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2039101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (GLOB_SFT_RST & t) {
2040101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
2041101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2042101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2043101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikdone:
2044101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	return rc;
2045101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2046101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
204747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
2048ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
2049ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
2050ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	void __iomem *port_mmio;
2051ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	u32 tmp;
2052ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2053ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(mmio + MV_RESET_CFG);
2054ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	if ((tmp & (1 << 0)) == 0) {
205547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->signal[idx].amps = 0x7 << 8;
2056ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		hpriv->signal[idx].pre = 0x1 << 5;
2057ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		return;
2058ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	}
2059ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2060ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	port_mmio = mv_port_base(mmio, idx);
2061ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(port_mmio + PHY_MODE2);
2062ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2063ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
2064ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
2065ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2066ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
206747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
2068ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
206947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
2070ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2071ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2072c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
20732a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
2074bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
2075c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
2076c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2077bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
207847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	int fix_phy_mode2 =
207947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
2080bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	int fix_phy_mode4 =
208147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
208247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	u32 m2, tmp;
208347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
208447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (fix_phy_mode2) {
208547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
208647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~(1 << 16);
208747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 |= (1 << 31);
208847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
208947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
209047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
209147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
209247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
209347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~((1 << 16) | (1 << 31));
209447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
209547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
209647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
209747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	}
209847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
209947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* who knows what this magic does */
210047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp = readl(port_mmio + PHY_MODE3);
210147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp &= ~0x7F800000;
210247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp |= 0x2A800000;
210347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(tmp, port_mmio + PHY_MODE3);
2104bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2105bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (fix_phy_mode4) {
210647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		u32 m4;
2107bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2108bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = readl(port_mmio + PHY_MODE4);
210947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
211047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
211147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			tmp = readl(port_mmio + 0x310);
2112bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2113bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = (m4 & ~(1 << 1)) | (1 << 0);
2114bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2115bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		writel(m4, port_mmio + PHY_MODE4);
211647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
211747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
211847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			writel(tmp, port_mmio + 0x310);
2119bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2120bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2121bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	/* Revert values of pre-emphasis and signal amps to the saved ones */
2122bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 = readl(port_mmio + PHY_MODE2);
2123bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2124bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 &= ~MV_M2_PREAMP_MASK;
21252a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].amps;
21262a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].pre;
212747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	m2 &= ~(1 << 16);
2128bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2129e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* according to mvSata 3.6.1, some IIE values are fixed */
2130e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (IS_GEN_IIE(hpriv)) {
2131e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 &= ~0xC30FF01F;
2132e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 |= 0x0000900F;
2133e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
2134e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2135bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	writel(m2, port_mmio + PHY_MODE2);
2136bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2137bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2138c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
2139c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no)
2140c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
2141c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port_no);
2142c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2143c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
2144c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2145ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv)) {
2146c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2147eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl |= (1 << 7);		/* enable gen2i speed */
2148eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2149c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2150c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
2151c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2152c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	udelay(25);		/* allow reset propagation */
2153c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2154c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	/* Spec never mentions clearing the bit.  Marvell's driver does
2155c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 * clear the bit, however.
2156c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 */
2157c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(0, port_mmio + EDMA_CMD_OFS);
2158c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2159c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->ops->phy_errata(hpriv, mmio, port_no);
2160c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2161ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2162c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mdelay(1);
2163c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
2164c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
216505b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
2166bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik *      mv_phy_reset - Perform eDMA reset followed by COMRESET
216705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
216805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
216905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Part of this is taken from __sata_phy_reset and modified to
217005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      not sleep since this routine gets called from interrupt level.
217105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
217205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
217305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.  This is coded to safe to call at
217405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt level, i.e. it does not sleep.
217531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ */
2176bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_phy_reset(struct ata_port *ap, unsigned int *class,
2177bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 unsigned long deadline)
217820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2179095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2180cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
218120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
218222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	int retry = 5;
218322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	u32 sstatus;
218420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
218520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
218620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2187da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2188da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2189da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2190da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2191da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2192da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2193da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2194da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
2195da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", status, serror, scontrol);
2196da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2197da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
219820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
219922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* Issue COMRESET via SControl */
220022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzikcomreset_retry:
220181952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
2202bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(1);
220322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
220481952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
2205bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(20);
220622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
220731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	do {
220881952c5497b40ae56835bd0d6537f8c6bdea07e7Tejun Heo		sata_scr_read(ap, SCR_STATUS, &sstatus);
220962f1d0e6de138b91d55fbd7d579c837ed62e9e31Andres Salomon		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
221031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
221122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2212bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(1);
2213c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	} while (time_before(jiffies, deadline));
221420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
221522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* work around errata */
2216ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv) &&
221722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
221822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (retry-- > 0))
221922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		goto comreset_retry;
2220095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2221da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2222da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2223da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2224da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2225da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2226da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2227da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2228da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
2229da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2230da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2231da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
223231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2233bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ata_port_offline(ap)) {
2234bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		*class = ATA_DEV_NONE;
223520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return;
223620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
223720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
223822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* even after SStatus reflects that device is ready,
223922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * it seems to take a while for link to be fully
224022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * established (and thus Status no longer 0x80/0x7F),
224122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * so we poll a bit for that, here.
224222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 */
224322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	retry = 20;
224422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	while (1) {
224522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		u8 drv_stat = ata_check_status(ap);
224622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
224722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2248bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(500);
224922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if (retry-- <= 0)
225022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2251bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (time_after(jiffies, deadline))
2252bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
225322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	}
225422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2255bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: if we passed the deadline, the following
2256bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * code probably produces an invalid result
2257bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
225820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2259bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* finally, read device signature from TF registers */
2260bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	*class = ata_dev_try_classify(ap, 0, NULL);
2261095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2262095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2263095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2264bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
2265095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2266bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	VPRINTK("EXIT\n");
226720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
226820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2269bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic int mv_prereset(struct ata_port *ap, unsigned long deadline)
227022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik{
2271bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp	= ap->private_data;
22729af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_eh_context *ehc = &ap->link.eh_context;
2273bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	int rc;
22740ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
2275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	rc = mv_stop_dma(ap);
2276bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (rc)
2277bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2278bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2279bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) {
2280bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
2281bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehc->i.action |= ATA_EH_HARDRESET;
2282bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2283bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2284bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* if we're about to do hardreset, nothing more to do */
2285bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ehc->i.action & ATA_EH_HARDRESET)
2286bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return 0;
2287bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2288bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (ata_port_online(ap))
2289bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = ata_wait_ready(ap, deadline);
2290bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
2291bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		rc = -ENODEV;
2292bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2293bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return rc;
229422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik}
229522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2296bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic int mv_hardreset(struct ata_port *ap, unsigned int *class,
2297bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			unsigned long deadline)
229831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
2299bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
23000d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
230131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2302bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(ap);
230331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2304bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_channel_reset(hpriv, mmio, ap->port_no);
230531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2306bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_phy_reset(ap, class, deadline);
2307bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2308bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return 0;
2309bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2310bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2311bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_postreset(struct ata_port *ap, unsigned int *classes)
2312bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2313bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 serr;
2314bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2315bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* print link status */
2316bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_print_link_status(ap);
231731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2318bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear SError */
2319bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_scr_read(ap, SCR_ERROR, &serr);
2320bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	sata_scr_write_flush(ap, SCR_ERROR, serr);
2321bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2322bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* bail out if no device is present */
2323bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
2324bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		DPRINTK("EXIT, no device\n");
2325bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
23269b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord	}
2327bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2328bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* set up device control */
2329bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
2330bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2331bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2332bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap)
2333bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2334bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_do_eh(ap, mv_prereset, ata_std_softreset,
2335bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		  mv_hardreset, mv_postreset);
2336bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2337bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2338bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_post_int_cmd(struct ata_queued_cmd *qc)
2339bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2340bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(qc->ap);
2341bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2342bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2343bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap)
2344bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2345bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2346bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2347bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask;
2348bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift;
2349bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2350bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2351bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2352bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2353bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0)
2354bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2355bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2356bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2357bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2358bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* disable assertion of portN err, done events */
2359bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2360bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
2361bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2362bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2363bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap)
2364bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2365bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2366bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2367bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2368bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
2369bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask, hc_irq_cause;
2370bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift, hc_port_no = ap->port_no;
2371bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2372bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2373bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2374bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2375bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0) {
2376bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2377bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hc_port_no -= 4;
2378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2379bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2380bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2381bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2382bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear EDMA errors on this port */
2383bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2384bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2385bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear pending irq events */
2386bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
2387bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << hc_port_no);	/* clear CRPB-done */
2388bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
2389bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
2390bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2391bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* enable assertion of portN err, done events */
2392bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2393bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
239431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
239531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
239605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
239705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_init - Perform some early initialization on a single port.
239805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port: libata data structure storing shadow register addresses
239905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port_mmio: base address of the port
240005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
240105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Initialize shadow register mmio addresses, clear outstanding
240205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts on the port, and unmask interrupts for the future
240305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      start of the port.
240405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
240505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
240605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
240705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
240831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
240920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
24100d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
241131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	unsigned serr_ofs;
241231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
24138b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* PIO related setup
241431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
241531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
24168b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->error_addr =
241731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
241831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
241931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
242031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
242131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
242231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
24238b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->status_addr =
242431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
242531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* special case: control/altstatus doesn't have ATA_REG_ address */
242631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
242731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
242831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* unused: */
24298d9db2d2fbae9e05022825c32f86e00c8e342860Randy Dunlap	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
243020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
243131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding port interrupt conditions */
243231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	serr_ofs = mv_scr_offset(SCR_ERROR);
243331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
243431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
243531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
243620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* unmask all EDMA error interrupts */
243731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
243820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24398b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
244031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_CFG_OFS),
244131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
244231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
244320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
244420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24454447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2446bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
24474447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
24484447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2449bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
2450bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2451bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	switch(board_idx) {
245247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	case chip_5080:
245347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2454ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
245547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
245644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
245747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x1:
245847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
245947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
246047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
246147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
246247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
246347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
246447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
246547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying 50XXB2 workarounds to unknown rev\n");
246647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
246747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
246847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		}
246947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		break;
247047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
2471bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_504x:
2472bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_508x:
247347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2474ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
2475bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
247644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
247747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x0:
247847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
247947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
248047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
248147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
248247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
248347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
248447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
248547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying B2 workarounds to unknown rev\n");
248647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
248747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
2488bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2489bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2490bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2491bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_604x:
2492bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_608x:
249347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv6xxx_ops;
2494ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_II;
249547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
249644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
249747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x7:
249847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
249947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
250047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x9:
250147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2502bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2503bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		default:
2504bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
250547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik				   "Applying B2 workarounds to unknown rev\n");
250647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
2507bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2508bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2509bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2510bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2511e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_7042:
2512e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_6042:
2513e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hpriv->ops = &mv6xxx_ops;
2514e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hp_flags |= MV_HP_GEN_IIE;
2515e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
251644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
2517e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x0:
2518e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_XX42A0;
2519e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2520e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x1:
2521e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2522e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2523e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		default:
2524e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
2525e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			   "Applying 60X1C0 workarounds to unknown rev\n");
2526e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2527e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2528e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		}
2529e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		break;
2530e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2531bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	default:
2532bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
2533bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		return 1;
2534bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2535bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2536bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	hpriv->hp_flags = hp_flags;
2537bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2538bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	return 0;
2539bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2540bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
254105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
254247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik *      mv_init_host - Perform some early initialization of the host.
25434447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *	@host: ATA host to initialize
25444447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @board_idx: controller index
254505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
254605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      If possible, do an early global reset of the host.  Then do
254705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      our port init and clear/unmask all/relevant host interrupts.
254805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
254905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
255005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
255105b308e1df6d9d673daedb517969241f41278b52Brett Russ */
25524447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_init_host(struct ata_host *host, unsigned int board_idx)
255320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
255420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	int rc = 0, n_hc, port, hc;
25554447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
25564447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
25574447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2558bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
255947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* global interrupt mask */
256047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
256147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
25624447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_chip_id(host, board_idx);
2563bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (rc)
2564bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		goto done;
2565bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25664447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_hc = mv_get_hc_count(host->ports[0]->flags);
2567bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25684447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++)
256947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops->read_preamp(hpriv, port, mmio);
257020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2571c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
257247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (rc)
257320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		goto done;
257420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2575522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_flash(hpriv, mmio);
2576522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_bus(pdev, mmio);
257747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	hpriv->ops->enable_leds(hpriv, mmio);
257820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
25794447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2580ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		if (IS_GEN_II(hpriv)) {
2581c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			void __iomem *port_mmio = mv_port_base(mmio, port);
2582c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
25832a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2584eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl |= (1 << 7);		/* enable gen2i speed */
2585eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
25862a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
25872a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		}
25882a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
2589c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		hpriv->ops->phy_errata(hpriv, mmio, port);
25902a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	}
25912a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
25924447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
25932a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		void __iomem *port_mmio = mv_port_base(mmio, port);
25944447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
259520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
259620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
259720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hc; hc++) {
259831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
259931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
260031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
260131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			"(before clear)=0x%08x\n", hc,
260231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_CFG_OFS),
260331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
260431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
260531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* Clear any currently outstanding hc interrupt conditions */
260631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
260720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
260820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
260931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding host interrupt conditions */
261031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
261131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
261231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and unmask interrupt generation for host regs */
261331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
2614fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik
2615ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2616fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2617fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	else
2618fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik		writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
261920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
262020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
26218b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		"PCI int cause/mask=0x%08x/0x%08x\n",
262220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
262320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
262420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + PCI_IRQ_CAUSE_OFS),
262520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		readl(mmio + PCI_IRQ_MASK_OFS));
2626bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
262731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russdone:
262820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return rc;
262920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
263020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
263105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
263205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_print_info - Dump key info to kernel log for perusal.
26334447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @host: ATA host to print info about
263405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
263505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      FIXME: complete this.
263605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
263705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
263805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
263905b308e1df6d9d673daedb517969241f41278b52Brett Russ */
26404447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic void mv_print_info(struct ata_host *host)
264131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
26424447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
26434447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
264444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	u8 scc;
2645c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	const char *scc_s, *gen;
264631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
264731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Use this to determine the HW stepping of the chip so we know
264831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * what errata to workaround
264931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
265031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
265131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (scc == 0)
265231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "SCSI";
265331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else if (scc == 0x01)
265431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "RAID";
265531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else
2656c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		scc_s = "?";
2657c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik
2658c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	if (IS_GEN_I(hpriv))
2659c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "I";
2660c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_II(hpriv))
2661c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "II";
2662c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_IIE(hpriv))
2663c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "IIE";
2664c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else
2665c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "?";
266631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2667a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	dev_printk(KERN_INFO, &pdev->dev,
2668c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
2669c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
267031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
267131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
267231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
267305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
267405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_init_one - handle a positive probe of a Marvell host
267505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pdev: PCI device found
267605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ent: PCI device ID entry for the matched host
267705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
267805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
267905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
268005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
268120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
268220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
268320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	static int printed_version = 0;
268420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int board_idx = (unsigned int)ent->driver_data;
26854447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
26864447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
26874447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv;
26884447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int n_ports, rc;
268920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2690a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	if (!printed_version++)
2691a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
269220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
26934447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
26944447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
26954447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
26964447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
26974447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
26984447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host || !hpriv)
26994447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
27004447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->private_data = hpriv;
27014447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
27024447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* acquire resources */
270324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
270424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
270520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return rc;
270620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27070d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
27080d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
270924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
27100d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
271124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
27124447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
271320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2714d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	rc = pci_go_64(pdev);
2715d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (rc)
2716d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		return rc;
2717d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
271820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* initialize adapter */
27194447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_init_host(host, board_idx);
272024dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
272124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
272220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
272331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Enable interrupts */
27246a59dcf8678cbc4106a8a6e158d7408a87691358Tejun Heo	if (msi && pci_enable_msi(pdev))
272531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pci_intx(pdev, 1);
272620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
272731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_pci_cfg(pdev, 0x68);
27284447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mv_print_info(host);
272920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27304447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	pci_set_master(pdev);
2731ea8b4db97aa41a66c05daa4055a1974692ccd52dJeff Garzik	pci_try_set_mwi(pdev);
27324447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
2733c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
273420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
273520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
273620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int __init mv_init(void)
273720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2738b7887196e38da54ff893897b80875d632d1a1114Pavel Roskin	return pci_register_driver(&mv_pci_driver);
273920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
274020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
274120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void __exit mv_exit(void)
274220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
274320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	pci_unregister_driver(&mv_pci_driver);
274420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
274520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
274620f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_AUTHOR("Brett Russ");
274720f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
274820f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_LICENSE("GPL");
274920f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DEVICE_TABLE(pci, mv_pci_tbl);
275020f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_VERSION(DRV_VERSION);
275120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2752ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikmodule_param(msi, int, 0444);
2753ddef9bb367b19383df627e388cb4c01c86ddba6cJeff GarzikMODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2754ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
275520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_init(mv_init);
275620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_exit(mv_exit);
2757