sata_mv.c revision 68d1d07b510bb57a504588adc2bd2758adea0965
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
321fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord  2) Improve/fix IRQ and error handling sequences.
331fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord
341fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord  3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
351fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord
361fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord  4) Think about TCQ support here, and for libata in general
371fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord  with controllers that suppport it via host-queuing hardware
381fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord  (a software-only implementation could be a nightmare).
394a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
404a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  5) Investigate problems with PCI Message Signalled Interrupts (MSI).
414a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
424a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  6) Add port multiplier support (intermediate)
434a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
444a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  8) Develop a low-power-consumption strategy, and implement it.
454a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
464a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  9) [Experiment, low priority] See if ATAPI can be supported using
474a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  "unknown FIS" or "vendor-specific FIS" support, or something creative
484a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  like that.
494a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
504a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  10) [Experiment, low priority] Investigate interrupt coalescing.
514a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  Quite often, especially with PCI Message Signalled Interrupts (MSI),
524a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  the overhead reduced by interrupt mitigation is quite often not
534a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  worth the latency cost.
544a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
554a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  11) [Experiment, Marvell value added] Is it possible to use target
564a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  mode to cross-connect two Linux boxes with Marvell cards?  If so,
574a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  creating LibATA target mode support would be very interesting.
584a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
594a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  Target mode, for those without docs, is the ability to directly
604a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik  connect two SATA controllers.
614a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
624a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik*/
634a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
644a05e2091709dbb22b86a1b3343cd3fa3c0d7a6bJeff Garzik
6520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/kernel.h>
6620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/module.h>
6720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/pci.h>
6820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/init.h>
6920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/blkdev.h>
7020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/delay.h>
7120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/interrupt.h>
728d8b60046d6a2328ca4b9031b4948084f775f607Andrew Morton#include <linux/dmapool.h>
7320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/dma-mapping.h>
74a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik#include <linux/device.h>
75f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#include <linux/platform_device.h>
76f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#include <linux/ata_platform.h>
7720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <scsi/scsi_host.h>
78193515d51ccb363165d6b09e9ba5c21089e34badJeff Garzik#include <scsi/scsi_cmnd.h>
796c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik#include <scsi/scsi_device.h>
8020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#include <linux/libata.h>
8120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ#define DRV_NAME	"sata_mv"
831fd2e1c242acb4a589d59c77853897bdbb599186Mark Lord#define DRV_VERSION	"1.20"
8420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
8520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russenum {
8620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* BAR's are enumerated in terms of pci_resource_start() terms */
8720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PRIMARY_BAR		= 0,	/* offset 0x10: memory space */
8820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IO_BAR		= 2,	/* offset 0x18: IO space */
8920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MISC_BAR		= 3,	/* offset 0x1c: FLASH, NVRAM, SRAM */
9020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
9120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MAJOR_REG_AREA_SZ	= 0x10000,	/* 64KB */
9220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_MINOR_REG_AREA_SZ	= 0x2000,	/* 8KB */
9320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
9420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_BASE		= 0,
9520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_IRQ_COAL_REG_BASE	= 0x18000,	/* 6xxx part only */
96615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE		= (MV_IRQ_COAL_REG_BASE + 0x08),
97615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_LO		= (MV_IRQ_COAL_REG_BASE + 0x88),
98615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_CAUSE_HI		= (MV_IRQ_COAL_REG_BASE + 0x8c),
99615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_THRESHOLD		= (MV_IRQ_COAL_REG_BASE + 0xcc),
100615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord	MV_IRQ_COAL_TIME_THRESHOLD	= (MV_IRQ_COAL_REG_BASE + 0xd0),
101615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
10220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC0_REG_BASE	= 0x20000,
103522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_FLASH_CTL		= 0x1046c,
104bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_GPIO_PORT_CTL	= 0x104f0,
105bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_RESET_CFG		= 0x180d8,
10620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
10720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PCI_REG_SZ		= MV_MAJOR_REG_AREA_SZ,
10820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_REG_SZ	= MV_MAJOR_REG_AREA_SZ,
10920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
11020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
11120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
11231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH		= 32,
11331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
11431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
11631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * CRPB needs alignment on a 256B boundary. Size == 256B
11731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
11831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
11931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
12031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
121da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	MV_MAX_SG_CT		= 256,
12231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
12331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
12420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORTS_PER_HC		= 4,
12520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
12620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_HC_SHIFT	= 2,
12731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
12820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_PORT_MASK		= 3,
12920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
13020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Host Flags */
13120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
13220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
1337bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	/* SoC integrated controllers, no PCI interface */
1347bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	MV_FLAG_SOC = (1 << 28),
1357bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
136c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	MV_COMMON_FLAGS		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
137bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
138bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  ATA_FLAG_PIO_POLLING,
13947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_6XXX_FLAGS		= MV_FLAG_IRQ_COALESCE,
14020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
14131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_FLAG_READ		= (1 << 0),
14231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_TAG_SHIFT		= 1,
143c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_IOID_SHIFT		= 6,	/* CRQB Gen-II/IIE IO Id shift */
144c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRQB_HOSTQ_SHIFT	= 17,	/* CRQB Gen-II/IIE HostQueTag shift */
14531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_ADDR_SHIFT	= 8,
14631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_CS		= (0x2 << 11),
14731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRQB_CMD_LAST		= (1 << 15),
14831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
14931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_FLAG_STATUS_SHIFT	= 8,
150c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_6	= 5,	/* CRPB Gen-II IO Id shift */
151c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	CRPB_IOID_SHIFT_7	= 7,	/* CRPB Gen-IIE IO Id shift */
15231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
15331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EPRD_FLAG_END_OF_TBL	= (1 << 31),
15431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
15520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* PCI interface registers */
15620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
15731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	PCI_COMMAND_OFS		= 0xc00,
15831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
15920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MAIN_CMD_STS_OFS	= 0xd30,
16020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	STOP_PCI_MASTER		= (1 << 2),
16120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_MASTER_EMPTY	= (1 << 3),
16220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GLOB_SFT_RST		= (1 << 4),
16320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
164522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MODE		= 0xd00,
165522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_EXP_ROM_BAR_CTL	= 0xd2c,
166522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_DISC_TIMER	= 0xd04,
167522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_MSI_TRIGGER	= 0xc38,
168522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_SERR_MASK	= 0xc28,
169522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_XBAR_TMOUT	= 0x1d04,
170522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_LOW_ADDRESS	= 0x1d40,
171522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_HIGH_ADDRESS	= 0x1d44,
172522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_ATTRIBUTE	= 0x1d48,
173522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	MV_PCI_ERR_COMMAND	= 0x1d50,
174522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
17502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCI_IRQ_CAUSE_OFS	= 0x1d58,
17602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCI_IRQ_MASK_OFS	= 0x1d5c,
17720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_UNMASK_ALL_IRQS	= 0x7fffff,	/* bits 22-0 */
17820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
17902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCIE_IRQ_CAUSE_OFS	= 0x1900,
18002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	PCIE_IRQ_MASK_OFS	= 0x1910,
181646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	PCIE_UNMASK_ALL_IRQS	= 0x40a,	/* assorted bits */
18202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
18320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
18420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
185f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
186f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
18720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_ERR		= (1 << 0),	/* shift by port # */
18820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORT0_DONE		= (1 << 1),	/* shift by port # */
18920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC0_IRQ_PEND		= 0x1ff,	/* bits 0-8 = HC0's ports */
19020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_SHIFT		= 9,		/* bits 9-17 = HC1's ports */
19120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PCI_ERR			= (1 << 18),
19220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_LO_DONE		= (1 << 19),	/* 6xxx: IRQ coalescing */
19320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TRAN_HI_DONE		= (1 << 20),	/* 6xxx: IRQ coalescing */
194fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_0_3_COAL_DONE	= (1 << 8),
195fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	PORTS_4_7_COAL_DONE	= (1 << 17),
19620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	PORTS_0_7_COAL_DONE	= (1 << 21),	/* 6xxx: IRQ coalescing */
19720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	GPIO_INT		= (1 << 22),
19820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SELF_INT		= (1 << 23),
19920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	TWSI_INT		= (1 << 24),
20020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_MAIN_RSVD		= (0x7f << 25),	/* bits 31-25 */
201fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_RSVD_5		= (0x1fff << 19), /* bits 31-19 */
202f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	HC_MAIN_RSVD_SOC 	= (0x3fffffb << 6),     /* bits 31-9, 7-6 */
2038b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	HC_MAIN_MASKED_IRQS	= (TRAN_LO_DONE | TRAN_HI_DONE |
20420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
20520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ				   HC_MAIN_RSVD),
206fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik	HC_MAIN_MASKED_IRQS_5	= (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
207fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik				   HC_MAIN_RSVD_5),
208f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
20920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATAHC registers */
21120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_CFG_OFS		= 0,
21220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_CAUSE_OFS	= 0x14,
21431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
21520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
21620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	DEV_IRQ			= (1 << 8),	/* shift by port # */
21720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
21820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Shadow block registers */
21931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_BLK_OFS		= 0x100,
22031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
22120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
22220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* SATA registers */
22320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
22420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	SATA_ACTIVE_OFS		= 0x350,
2250c58912e192fc3a4835d772aafa40b72552b819fMark Lord	SATA_FIS_IRQ_CAUSE_OFS	= 0x364,
22647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	PHY_MODE3		= 0x310,
227bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE4		= 0x314,
228bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	PHY_MODE2		= 0x330,
229c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_MODE		= 0x74,
230c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_LT_MODE		= 0x30,
231c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	MV5_PHY_CTL		= 0x0C,
232bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	SATA_INTERFACE_CTL	= 0x050,
233bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
234bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	MV_M2_PREAMP_MASK	= 0x7e0,
23520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
23620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Port registers */
23720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_CFG_OFS		= 0,
2380c58912e192fc3a4835d772aafa40b72552b819fMark Lord	EDMA_CFG_Q_DEPTH	= 0x1f,		/* max device queue depth */
2390c58912e192fc3a4835d772aafa40b72552b819fMark Lord	EDMA_CFG_NCQ		= (1 << 5),	/* for R/W FPDMA queued */
2400c58912e192fc3a4835d772aafa40b72552b819fMark Lord	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),	/* continue on error */
2410c58912e192fc3a4835d772aafa40b72552b819fMark Lord	EDMA_CFG_RD_BRST_EXT	= (1 << 11),	/* read burst 512B */
2420c58912e192fc3a4835d772aafa40b72552b819fMark Lord	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),	/* write buffer 512B */
24320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
24420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
24520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
2466c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
2476c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
2486c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV		= (1 << 2),	/* device error */
2496c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
2506c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
2516c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
252c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
253c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
2546c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
255c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
2566c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
2576c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
2586c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
2596c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
260646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
2616c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
262646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_RX_0	= (1 << 13),	/* transient: CRC err */
263646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_RX_1	= (1 << 14),	/* transient: FIFO err */
264646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),	/* fatal: caught SYNC */
265646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_RX_3	= (1 << 16),	/* transient: FIS rx err */
266646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
2676c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
268646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
2696c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
270646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_TX_0	= (1 << 21),	/* transient: CRC err */
271646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_TX_1	= (1 << 22),	/* transient: FIFO err */
272646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_TX_2	= (1 << 23),	/* transient: caught SYNC */
273646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_TX_3	= (1 << 24),	/* transient: caught DMAT */
274646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_LNK_CTRL_TX_4	= (1 << 25),	/* transient: FIS collision */
275646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
2766c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
277646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
2786c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
279c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_OVERRUN_5	= (1 << 5),
280c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	EDMA_ERR_UNDERRUN_5	= (1 << 6),
281646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
282646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	EDMA_ERR_IRQ_TRANSIENT  = EDMA_ERR_LNK_CTRL_RX_0 |
283646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord				  EDMA_ERR_LNK_CTRL_RX_1 |
284646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord				  EDMA_ERR_LNK_CTRL_RX_3 |
285646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord				  EDMA_ERR_LNK_CTRL_TX,
286646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord
287bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
288bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
289bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
290bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
291bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SERR |
292bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS |
2936c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
294bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
295bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
296bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY |
297bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_CTRL_RX_2 |
298bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_RX |
299bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_LNK_DATA_TX |
300bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_TRANS_PROTO,
301bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	EDMA_EH_FREEZE_5	= EDMA_ERR_D_PAR |
302bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_PRD_PAR |
303bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_DCON |
304bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_DEV_CON |
305bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_OVERRUN_5 |
306bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_UNDERRUN_5 |
307bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_SELF_DIS_5 |
3086c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik				  EDMA_ERR_CRQB_PAR |
309bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_CRPB_PAR |
310bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_INTRL_PAR |
311bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				  EDMA_ERR_IORDY,
31220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
31331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
31431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
31531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
31631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
31731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_REQ_Q_PTR_SHIFT	= 5,
31831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
31931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
32031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
32131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
32231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	EDMA_RSP_Q_PTR_SHIFT	= 3,
32331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
3240ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
3250ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_EN			= (1 << 0),	/* enable EDMA */
3260ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
3270ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
32820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
329c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	EDMA_IORDY_TMOUT	= 0x34,
330bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	EDMA_ARB_CFG		= 0x38,
331bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
33231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Host private flags (hp_flags) */
33331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	MV_HP_FLAG_MSI		= (1 << 0),
33447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB0	= (1 << 1),
33547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_50XXB2	= (1 << 2),
33647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1B2	= (1 << 3),
33747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	MV_HP_ERRATA_60X1C0	= (1 << 4),
338e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	MV_HP_ERRATA_XX42A0	= (1 << 5),
3390ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
3400ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
3410ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
34202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	MV_HP_PCIE		= (1 << 9),	/* PCIe bus/regs: 7042 */
34320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
34431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Port private flags (pp_flags) */
3450ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
346721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	MV_PP_FLAG_NCQ_EN	= (1 << 1),	/* is EDMA set up for NCQ? */
3470ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
34820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
34920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
350ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
351ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
352e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
3537bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
354bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
355095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzikenum {
356baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	/* DMA boundary 0xffff is required by the s/g splitting
357baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 * we need on /length/ in mv_fill-sg().
358baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	 */
359baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	MV_DMA_BOUNDARY		= 0xffffU,
360095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3610ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* mask of register bits containing lower 32 bits
3620ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 * of EDMA request queue DMA address
3630ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	 */
364095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
365095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
3660ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	/* ditto, for response queue */
367095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
368095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik};
369095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
370522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikenum chip_type {
371522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_504x,
372522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_508x,
373522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_5080,
374522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_604x,
375522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	chip_608x,
376e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_6042,
377e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	chip_7042,
378f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	chip_soc,
379522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik};
380522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
38131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ReQuest Block: 32B */
38231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crqb {
383e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr;
384e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			sg_addr_hi;
385e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ctrl_flags;
386e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			ata_cmd[11];
38731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
38820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
389e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstruct mv_crqb_iie {
390e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
391e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
392e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags;
393e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			len;
394e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			ata_cmd[4];
395e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
396e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
39731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* Command ResPonse Block: 8B */
39831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_crpb {
399e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			id;
400e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16			flags;
401e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			tmstmp;
40220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
40320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
40431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
40531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_sg {
406e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr;
407e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			flags_size;
408e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			addr_hi;
409e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le32			reserved;
41031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
41120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
41231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstruct mv_port_priv {
41331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crqb		*crqb;
41431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crqb_dma;
41531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_crpb		*crpb;
41631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	dma_addr_t		crpb_dma;
417eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	struct mv_sg		*sg_tbl[MV_MAX_Q_DEPTH];
418eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	dma_addr_t		sg_tbl_dma[MV_MAX_Q_DEPTH];
419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
420bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		req_idx;
421bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int		resp_idx;
422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
42331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32			pp_flags;
42431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ};
42531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
426bca1c4eb9411533d613123618c0d127fae532595Jeff Garzikstruct mv_port_signal {
427bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			amps;
428bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32			pre;
429bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik};
430bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
43102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lordstruct mv_host_priv {
43202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			hp_flags;
43302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_port_signal	signal[8];
43402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	const struct mv_hw_ops	*ops;
435f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	int			n_ports;
436f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem		*base;
437f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem		*main_cause_reg_addr;
438f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem		*main_mask_reg_addr;
43902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			irq_cause_ofs;
44002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			irq_mask_ofs;
44102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	u32			unmask_all_irqs;
442da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	/*
443da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	 * These consistent DMA memory pools give us guaranteed
444da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	 * alignment for hardware-accessed data structures,
445da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	 * and less memory waste in accomplishing the alignment.
446da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	 */
447da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	struct dma_pool		*crqb_pool;
448da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	struct dma_pool		*crpb_pool;
449da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	struct dma_pool		*sg_tbl_pool;
45002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord};
45102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
45247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstruct mv_hw_ops {
4532a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
4542a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
45547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
45647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
45747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
458c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
459c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
460522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
4617bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
46247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
46347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
464da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
465da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
466da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
467da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
46831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap);
46931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap);
47031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc);
471e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc);
4729a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap);
474bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap);
475bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap);
476f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lordstatic void mv6_dev_config(struct ata_device *dev);
47720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
4782a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4792a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
48047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
48147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
48247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
483c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
484c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
485522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
4867bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic void mv5_reset_bus(struct ata_host *host, void __iomem *mmio);
48747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
4882a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
4892a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port);
49047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
49147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
49247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   void __iomem *mmio);
493c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
494c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc);
495522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
496f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_enable_leds(struct mv_host_priv *hpriv,
497f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				      void __iomem *mmio);
498f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
499f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				      void __iomem *mmio);
500f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_soc_reset_hc(struct mv_host_priv *hpriv,
501f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				  void __iomem *mmio, unsigned int n_hc);
502f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_flash(struct mv_host_priv *hpriv,
503f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				      void __iomem *mmio);
504f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio);
5057bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
506c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
507c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no);
508721091685f853ba4e6c49f26f989db0b1a811250Mark Lordstatic void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
509721091685f853ba4e6c49f26f989db0b1a811250Mark Lord			void __iomem *port_mmio, int want_ncq);
510721091685f853ba4e6c49f26f989db0b1a811250Mark Lordstatic int __mv_stop_dma(struct ata_port *ap);
51147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
512eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
513eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord * because we have to allow room for worst case splitting of
514eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord * PRDs for 64K boundaries in mv_fill_sg().
515eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord */
516c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv5_sht = {
51768d1d07b510bb57a504588adc2bd2758adea0965Tejun Heo	ATA_BASE_SHT(DRV_NAME),
518baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
519c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	.dma_boundary		= MV_DMA_BOUNDARY,
520c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik};
521c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
522c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic struct scsi_host_template mv6_sht = {
52368d1d07b510bb57a504588adc2bd2758adea0965Tejun Heo	ATA_NCQ_SHT(DRV_NAME),
524138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	.can_queue		= MV_MAX_Q_DEPTH - 1,
525baf14aa14efcfdb5a74d5cf804691086c6bec743Jeff Garzik	.sg_tablesize		= MV_MAX_SG_CT / 2,
52620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dma_boundary		= MV_DMA_BOUNDARY,
52720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
52820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
529c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv5_ops = {
530c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_load		= ata_tf_load,
531c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.tf_read		= ata_tf_read,
532c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.check_status		= ata_check_status,
533c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.exec_command		= ata_exec_command,
534c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.dev_select		= ata_std_dev_select,
535c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
536c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_prep		= mv_qc_prep,
537c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.qc_issue		= mv_qc_issue,
5380d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
539c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
540358f9a77a668660729e705fde9c3cf69f013aa98Tejun Heo	.irq_clear		= ata_noop_irq_clear,
541246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
542c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
543bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
544bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
545bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
546bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
547c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_read		= mv5_scr_read,
548c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.scr_write		= mv5_scr_write,
549c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
550c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_start		= mv_port_start,
551c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	.port_stop		= mv_port_stop,
552c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik};
553c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
554c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic const struct ata_port_operations mv6_ops = {
555f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	.dev_config             = mv6_dev_config,
55620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_load		= ata_tf_load,
55720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.tf_read		= ata_tf_read,
55820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.check_status		= ata_check_status,
55920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.exec_command		= ata_exec_command,
56020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.dev_select		= ata_std_dev_select,
56120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
56231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_prep		= mv_qc_prep,
56331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.qc_issue		= mv_qc_issue,
5640d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
56520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
566358f9a77a668660729e705fde9c3cf69f013aa98Tejun Heo	.irq_clear		= ata_noop_irq_clear,
567246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
56820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
569bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
570bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
571bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
572138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	.qc_defer		= ata_std_qc_defer,
573bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
57420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_read		= mv_scr_read,
57520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	.scr_write		= mv_scr_write,
57620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
57731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_start		= mv_port_start,
57831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	.port_stop		= mv_port_stop,
57920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
58020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
581e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic const struct ata_port_operations mv_iie_ops = {
582e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_load		= ata_tf_load,
583e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.tf_read		= ata_tf_read,
584e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.check_status		= ata_check_status,
585e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.exec_command		= ata_exec_command,
586e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.dev_select		= ata_std_dev_select,
587e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
588e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_prep		= mv_qc_prep_iie,
589e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.qc_issue		= mv_qc_issue,
5900d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	.data_xfer		= ata_data_xfer,
591e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
592358f9a77a668660729e705fde9c3cf69f013aa98Tejun Heo	.irq_clear		= ata_noop_irq_clear,
593246ce3b675843e0369643cceb4faeb6cf6d19a30Akira Iguchi	.irq_on			= ata_irq_on,
594e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
595bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.error_handler		= mv_error_handler,
596bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.freeze			= mv_eh_freeze,
597bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	.thaw			= mv_eh_thaw,
598138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	.qc_defer		= ata_std_qc_defer,
599bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
600e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_read		= mv_scr_read,
601e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.scr_write		= mv_scr_write,
602e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
603e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_start		= mv_port_start,
604e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	.port_stop		= mv_port_stop,
605e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik};
606e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
60798ac62defe529d04a192688f40d801a2d8fbcf98Arjan van de Venstatic const struct ata_port_info mv_port_info[] = {
60820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_504x */
609cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= MV_COMMON_FLAGS,
61031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
611bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
612c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
61320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
61420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_508x */
615c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
61631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
617bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
618c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
61920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
62047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	{  /* chip_5080 */
621c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
62247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
623bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
624c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv5_ops,
62547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	},
62620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_604x */
627138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
628138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord				  ATA_FLAG_NCQ,
62931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
630bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
631c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
63220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
63320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	{  /* chip_608x */
634c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
635138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord				  ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
63631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		.pio_mask	= 0x1f,	/* pio0-4 */
637bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
638c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		.port_ops	= &mv6_ops,
63920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	},
640e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_6042 */
641138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
642138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord				  ATA_FLAG_NCQ,
643e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
644bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
645e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
646e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
647e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	{  /* chip_7042 */
648138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
649138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord				  ATA_FLAG_NCQ,
650e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.pio_mask	= 0x1f,	/* pio0-4 */
651bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
652e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		.port_ops	= &mv_iie_ops,
653e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	},
654f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	{  /* chip_soc */
655f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		.flags = MV_COMMON_FLAGS | MV_FLAG_SOC,
656f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		.pio_mask = 0x1f,      /* pio0-4 */
657f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		.udma_mask = ATA_UDMA6,
658f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		.port_ops = &mv_iie_ops,
659f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	},
66020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
66120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
6623b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id mv_pci_tbl[] = {
6632d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
6642d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
6652d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
6662d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
667cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	/* RocketRAID 1740/174x have different identifiers */
668cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
669cfbf723eb7928879292ee71fa0d118fc4e37b8c9Alan Cox	{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
6702d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6712d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
6722d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
6732d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
6742d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
6752d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
6762d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
6772d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
6782d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
679d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	/* Adaptec 1430SA */
680d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger	{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
681d9f9c6bc91c14f53ffa782ffcd42259ecae1d38cFlorian Attenberger
68202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	/* Marvell 7042 support */
6836a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
6846a3d586d8e8a50e4cfd7f8c36d82a53c5614e05bMorrison, Tom
68502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	/* Highpoint RocketRAID PCIe series */
68602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	{ PCI_VDEVICE(TTI, 0x2300), chip_7042 },
68702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
68802a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord
6892d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik	{ }			/* terminate list */
69020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ};
69120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
69247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv5xxx_ops = {
69347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv5_phy_errata,
69447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv5_enable_leds,
69547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv5_read_preamp,
69647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv5_reset_hc,
697522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv5_reset_flash,
698522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv5_reset_bus,
69947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
70047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
70147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic const struct mv_hw_ops mv6xxx_ops = {
70247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.phy_errata		= mv6_phy_errata,
70347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.enable_leds		= mv6_enable_leds,
70447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.read_preamp		= mv6_read_preamp,
70547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	.reset_hc		= mv6_reset_hc,
706522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_flash		= mv6_reset_flash,
707522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	.reset_bus		= mv_reset_pci_bus,
70847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik};
70947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
710f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic const struct mv_hw_ops mv_soc_ops = {
711f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.phy_errata		= mv6_phy_errata,
712f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.enable_leds		= mv_soc_enable_leds,
713f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.read_preamp		= mv_soc_read_preamp,
714f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.reset_hc		= mv_soc_reset_hc,
715f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.reset_flash		= mv_soc_reset_flash,
716f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.reset_bus		= mv_soc_reset_bus,
717f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara};
718f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
71920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ/*
72020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ * Functions
72120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ */
72220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
72320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void writelfl(unsigned long data, void __iomem *addr)
72420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
72520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	writel(data, addr);
72620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	(void) readl(addr);	/* flush to avoid PCI posted write */
72720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
72820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
72920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
73020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
73120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
73220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
73320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
734c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hc_from_port(unsigned int port)
735c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
736c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port >> MV_PORT_HC_SHIFT;
737c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
738c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
739c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline unsigned int mv_hardport_from_port(unsigned int port)
740c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
741c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return port & MV_PORT_MASK;
742c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
743c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
744c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic inline void __iomem *mv_hc_base_from_port(void __iomem *base,
745c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik						 unsigned int port)
746c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
747c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return mv_hc_base(base, mv_hc_from_port(port));
748c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
749c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
75020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
75120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
752c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return  mv_hc_base_from_port(base, port) +
7538b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		MV_SATAHC_ARBTR_REG_SZ +
754c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
75520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
75620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
757f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic inline void __iomem *mv_host_base(struct ata_host *host)
758f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
759f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = host->private_data;
760f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return hpriv->base;
761f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
762f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
76320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic inline void __iomem *mv_ap_base(struct ata_port *ap)
76420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
765f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return mv_port_base(mv_host_base(ap->host), ap->port_no);
76620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
76720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
768cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic inline int mv_get_hc_count(unsigned long port_flags)
76931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
770cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
77131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
77231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
773c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzikstatic void mv_set_edma_ptrs(void __iomem *port_mmio,
774c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_host_priv *hpriv,
775c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			     struct mv_port_priv *pp)
776c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik{
777bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 index;
778bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
779c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
780c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize request queue
781c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
782bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
783bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
784c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crqb_dma & 0x3ff);
785c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
786bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
787c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
788c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
789c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
790bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crqb_dma & 0xffffffff) | index,
791c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
792c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
793bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
794c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
795c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	/*
796c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 * initialize response queue
797c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	 */
798bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
799bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
800c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	WARN_ON(pp->crpb_dma & 0xff);
801c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
802c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
803c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
804bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & 0xffffffff) | index,
805c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik			 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
806c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	else
807bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
808c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
809bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
810c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
811c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik}
812c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
81305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
81405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_start_dma - Enable eDMA engine
81505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @base: port base address
81605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pp: port private data
81705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
818beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
819beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
82005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
82105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
82205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
82305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
8240c58912e192fc3a4835d772aafa40b72552b819fMark Lordstatic void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
825721091685f853ba4e6c49f26f989db0b1a811250Mark Lord			 struct mv_port_priv *pp, u8 protocol)
82620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
827721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	int want_ncq = (protocol == ATA_PROT_NCQ);
828721091685f853ba4e6c49f26f989db0b1a811250Mark Lord
829721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
830721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		int using_ncq = ((pp->pp_flags & MV_PP_FLAG_NCQ_EN) != 0);
831721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		if (want_ncq != using_ncq)
832721091685f853ba4e6c49f26f989db0b1a811250Mark Lord			__mv_stop_dma(ap);
833721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	}
834c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
8350c58912e192fc3a4835d772aafa40b72552b819fMark Lord		struct mv_host_priv *hpriv = ap->host->private_data;
8360c58912e192fc3a4835d772aafa40b72552b819fMark Lord		int hard_port = mv_hardport_from_port(ap->port_no);
8370c58912e192fc3a4835d772aafa40b72552b819fMark Lord		void __iomem *hc_mmio = mv_hc_base_from_port(
8380fca0d6f2ce3336022a22bc7fc2e009e599e63a4Saeed Bishara					mv_host_base(ap->host), hard_port);
8390c58912e192fc3a4835d772aafa40b72552b819fMark Lord		u32 hc_irq_cause, ipending;
8400c58912e192fc3a4835d772aafa40b72552b819fMark Lord
841bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* clear EDMA event indicators, if any */
842f630d562829fcd8160a118f98c1e5b9cdb4e703eMark Lord		writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
843bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
8440c58912e192fc3a4835d772aafa40b72552b819fMark Lord		/* clear EDMA interrupt indicator, if any */
8450c58912e192fc3a4835d772aafa40b72552b819fMark Lord		hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
8460c58912e192fc3a4835d772aafa40b72552b819fMark Lord		ipending = (DEV_IRQ << hard_port) |
8470c58912e192fc3a4835d772aafa40b72552b819fMark Lord				(CRPB_DMA_DONE << hard_port);
8480c58912e192fc3a4835d772aafa40b72552b819fMark Lord		if (hc_irq_cause & ipending) {
8490c58912e192fc3a4835d772aafa40b72552b819fMark Lord			writelfl(hc_irq_cause & ~ipending,
8500c58912e192fc3a4835d772aafa40b72552b819fMark Lord				 hc_mmio + HC_IRQ_CAUSE_OFS);
8510c58912e192fc3a4835d772aafa40b72552b819fMark Lord		}
8520c58912e192fc3a4835d772aafa40b72552b819fMark Lord
853721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		mv_edma_cfg(pp, hpriv, port_mmio, want_ncq);
8540c58912e192fc3a4835d772aafa40b72552b819fMark Lord
8550c58912e192fc3a4835d772aafa40b72552b819fMark Lord		/* clear FIS IRQ Cause */
8560c58912e192fc3a4835d772aafa40b72552b819fMark Lord		writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
8570c58912e192fc3a4835d772aafa40b72552b819fMark Lord
858f630d562829fcd8160a118f98c1e5b9cdb4e703eMark Lord		mv_set_edma_ptrs(port_mmio, hpriv, pp);
859bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
860f630d562829fcd8160a118f98c1e5b9cdb4e703eMark Lord		writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
861afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
862afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
863f630d562829fcd8160a118f98c1e5b9cdb4e703eMark Lord	WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
86420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
86520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
86605b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
8670ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik *      __mv_stop_dma - Disable eDMA engine
86805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
86905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
870beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      Verify the local cache of the eDMA state is accurate with a
871beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo *      WARN_ON.
87205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
87305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
87405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
87505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
8760ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int __mv_stop_dma(struct ata_port *ap)
87720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
87831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
87931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp	= ap->private_data;
88031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 reg;
881c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	int i, err = 0;
88231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
8834537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
884afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ		/* Disable EDMA if active.   The disable bit auto clears.
88531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
88631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
88731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
888afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	} else {
889beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo		WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
8902dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	}
8918b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
89231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* now properly wait for the eDMA to stop */
89331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (i = 1000; i > 0; i--) {
89431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		reg = readl(port_mmio + EDMA_CMD_OFS);
8954537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik		if (!(reg & EDMA_EN))
89631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
8974537deb5e90b717a725b3d74b58b4bb1d28443d0Jeff Garzik
89831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		udelay(100);
89931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
90031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
901c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	if (reg & EDMA_EN) {
902f15a1dafed22d5037e0feea7528e1eeb28a1a7a3Tejun Heo		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
903c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik		err = -EIO;
90431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
905c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik
906c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	return err;
90720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
90820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
9090ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzikstatic int mv_stop_dma(struct ata_port *ap)
9100ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik{
9110ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
9120ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	int rc;
9130ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
9140ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
9150ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	rc = __mv_stop_dma(ap);
9160ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
9170ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
9180ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	return rc;
9190ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik}
9200ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
9218a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#ifdef ATA_DEBUG
92231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_mem(void __iomem *start, unsigned bytes)
92320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
92431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
92531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
92631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%p: ", start + b);
92731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
9282dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			printk("%08x ", readl(start + b));
92931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
93031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
93131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
93231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
93331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
9348a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik#endif
9358a70f8dc08dd40b7f8ac77280eaa99a8c6bc46f4Jeff Garzik
93631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
93731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
93831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
93931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int b, w;
94031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u32 dw;
94131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (b = 0; b < bytes; ) {
94231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("%02x: ", b);
94331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		for (w = 0; b < bytes && w < 4; w++) {
9442dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			(void) pci_read_config_dword(pdev, b, &dw);
9452dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik			printk("%08x ", dw);
94631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			b += sizeof(u32);
94731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		}
94831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		printk("\n");
94931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
95031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
95131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
95231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_dump_all_regs(void __iomem *mmio_base, int port,
95331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			     struct pci_dev *pdev)
95431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
95531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#ifdef ATA_DEBUG
9568b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	void __iomem *hc_base = mv_hc_base(mmio_base,
95731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ					   port >> MV_PORT_HC_SHIFT);
95831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_base;
95931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	int start_port, num_ports, p, start_hc, num_hcs, hc;
96031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
96131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (0 > port) {
96231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = start_port = 0;
96331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = 8;		/* shld be benign for 4 port devs */
96431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_hcs = 2;
96531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	} else {
96631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_hc = port >> MV_PORT_HC_SHIFT;
96731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		start_port = port;
96831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports = num_hcs = 1;
96931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
9708b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	DPRINTK("All registers for port(s) %u-%u:\n", start_port,
97131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		num_ports > 1 ? num_ports - 1 : start_port);
97231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
97331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (NULL != pdev) {
97431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("PCI config space regs:\n");
97531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_pci_cfg(pdev, 0x68);
97631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
97731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	DPRINTK("PCI regs:\n");
97831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xc00, 0x3c);
97931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xd00, 0x34);
98031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0xf00, 0x4);
98131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_mem(mmio_base+0x1d00, 0x6c);
98231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
983d220c37e0a3c9a47ae00e87e044d963b3ea040bcDan Aloni		hc_base = mv_hc_base(mmio_base, hc);
98431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		DPRINTK("HC regs (HC %i):\n", hc);
98531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(hc_base, 0x1c);
98631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
98731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	for (p = start_port; p < start_port + num_ports; p++) {
98831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port_base = mv_port_base(mmio_base, p);
9892dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		DPRINTK("EDMA regs (port %i):\n", p);
99031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base, 0x54);
9912dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		DPRINTK("SATA regs (port %i):\n", p);
99231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_dump_mem(port_base+0x300, 0x60);
99331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
99431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ#endif
99520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
99620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
99720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic unsigned int mv_scr_offset(unsigned int sc_reg_in)
99820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
99920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs;
100020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
100120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	switch (sc_reg_in) {
100220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_STATUS:
100320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_CONTROL:
100420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ERROR:
100520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
100620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
100720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	case SCR_ACTIVE:
100820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = SATA_ACTIVE_OFS;   /* active is not with the others */
100920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
101020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	default:
101120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		ofs = 0xffffffffU;
101220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		break;
101320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
101420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return ofs;
101520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
101620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1017da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
101820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
101920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
102020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1021da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1022da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(mv_ap_base(ap) + ofs);
1023da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1024da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1025da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
102620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
102720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1028da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
102920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
103020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int ofs = mv_scr_offset(sc_reg_in);
103120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1032da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
103320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		writelfl(val, mv_ap_base(ap) + ofs);
1034da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1035da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1036da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
103720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
103820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1039f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lordstatic void mv6_dev_config(struct ata_device *adev)
1040f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord{
1041f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	/*
1042f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	 * We don't have hob_nsect when doing NCQ commands on Gen-II.
1043f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	 * See mv_qc_prep() for more info.
1044f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	 */
1045f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord	if (adev->flags & ATA_DFLAG_NCQ)
1046f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord		if (adev->max_sectors > ATA_MAX_SECTORS)
1047f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord			adev->max_sectors = ATA_MAX_SECTORS;
1048f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord}
1049f273827e2aadcf2f74a7bdc9ad715a1b20ea7ddaMark Lord
1050721091685f853ba4e6c49f26f989db0b1a811250Mark Lordstatic void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
1051721091685f853ba4e6c49f26f989db0b1a811250Mark Lord			void __iomem *port_mmio, int want_ncq)
1052e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
10530c58912e192fc3a4835d772aafa40b72552b819fMark Lord	u32 cfg;
1054e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1055e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* set up non-NCQ EDMA configuration */
10560c58912e192fc3a4835d772aafa40b72552b819fMark Lord	cfg = EDMA_CFG_Q_DEPTH;		/* always 0x1f for *all* chips */
1057e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
10580c58912e192fc3a4835d772aafa40b72552b819fMark Lord	if (IS_GEN_I(hpriv))
1059e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 8);	/* enab config burst size mask */
1060e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
10610c58912e192fc3a4835d772aafa40b72552b819fMark Lord	else if (IS_GEN_II(hpriv))
1062e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
1063e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1064e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	else if (IS_GEN_IIE(hpriv)) {
1065e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
1066e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
1067e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		cfg |= (1 << 18);	/* enab early completion */
1068e728eabea110da90e69c05855e3a11174edb77efJeff Garzik		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
1069e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
1070e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1071721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	if (want_ncq) {
1072721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		cfg |= EDMA_CFG_NCQ;
1073721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		pp->pp_flags |=  MV_PP_FLAG_NCQ_EN;
1074721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	} else
1075721091685f853ba4e6c49f26f989db0b1a811250Mark Lord		pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
1076721091685f853ba4e6c49f26f989db0b1a811250Mark Lord
1077e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
1078e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1079e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1080da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lordstatic void mv_port_free_dma_mem(struct ata_port *ap)
1081da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord{
1082da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	struct mv_host_priv *hpriv = ap->host->private_data;
1083da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	struct mv_port_priv *pp = ap->private_data;
1084eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	int tag;
1085da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord
1086da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	if (pp->crqb) {
1087da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma);
1088da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		pp->crqb = NULL;
1089da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	}
1090da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	if (pp->crpb) {
1091da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma);
1092da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		pp->crpb = NULL;
1093da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	}
1094eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	/*
1095eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 * For GEN_I, there's no NCQ, so we have only a single sg_tbl.
1096eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 * For later hardware, we have one unique sg_tbl per NCQ tag.
1097eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 */
1098eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
1099eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		if (pp->sg_tbl[tag]) {
1100eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			if (tag == 0 || !IS_GEN_I(hpriv))
1101eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord				dma_pool_free(hpriv->sg_tbl_pool,
1102eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord					      pp->sg_tbl[tag],
1103eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord					      pp->sg_tbl_dma[tag]);
1104eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			pp->sg_tbl[tag] = NULL;
1105eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		}
1106da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	}
1107da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord}
1108da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord
110905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
111005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_start - Port specific init/start routine.
111105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
111205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
111305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Allocate and point to DMA memory, init port private memory,
111405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      zero indices.
111505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
111605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
111705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
111805b308e1df6d9d673daedb517969241f41278b52Brett Russ */
111931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic int mv_port_start(struct ata_port *ap)
112031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1121cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct device *dev = ap->host->dev;
1122cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
112331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp;
112431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
11250ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	unsigned long flags;
1126dde2020754aeb14e17052d61784dcb37f252aac2James Bottomley	int tag;
112731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
112824dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
11296037d6bbdff65eb5a84fe35e140f4da4f7cc103aJeff Garzik	if (!pp)
113024dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENOMEM;
1131da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	ap->private_data = pp;
113231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1133da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
1134da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	if (!pp->crqb)
1135da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		return -ENOMEM;
1136da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	memset(pp->crqb, 0, MV_CRQB_Q_SZ);
113731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1138da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma);
1139da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	if (!pp->crpb)
1140da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		goto out_port_free_dma_mem;
1141da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	memset(pp->crpb, 0, MV_CRPB_Q_SZ);
114231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1143eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	/*
1144eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
1145eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 * For later hardware, we need one unique sg_tbl per NCQ tag.
1146eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	 */
1147eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
1148eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		if (tag == 0 || !IS_GEN_I(hpriv)) {
1149eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool,
1150eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord					      GFP_KERNEL, &pp->sg_tbl_dma[tag]);
1151eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			if (!pp->sg_tbl[tag])
1152eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord				goto out_port_free_dma_mem;
1153eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		} else {
1154eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			pp->sg_tbl[tag]     = pp->sg_tbl[0];
1155eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord			pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
1156eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		}
1157eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	}
115831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11590ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_lock_irqsave(&ap->host->lock, flags);
11600ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
1161721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	mv_edma_cfg(pp, hpriv, port_mmio, 0);
1162c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	mv_set_edma_ptrs(port_mmio, hpriv, pp);
116331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
11640ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik	spin_unlock_irqrestore(&ap->host->lock, flags);
11650ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
116631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Don't turn on EDMA here...do it before DMA commands only.  Else
116731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * we'll be unable to send non-data, PIO, etc due to restricted access
116831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * to shadow regs.
116931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
117031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
1171da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord
1172da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lordout_port_free_dma_mem:
1173da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	mv_port_free_dma_mem(ap);
1174da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	return -ENOMEM;
117531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
117631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
117705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
117805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_stop - Port specific cleanup/stop routine.
117905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
118005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
118105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Stop DMA, cleanup port memory.
118205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
118305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
1184cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine uses the host lock to protect the DMA stop.
118505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
118631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_stop(struct ata_port *ap)
118731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
118831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_stop_dma(ap);
1189da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	mv_port_free_dma_mem(ap);
119031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
119131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
119205b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
119305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
119405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command whose SG list to source from
119505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
119605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Populate the SG list and mark the last entry.
119705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
119805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
119905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
120005b308e1df6d9d673daedb517969241f41278b52Brett Russ */
12016c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzikstatic void mv_fill_sg(struct ata_queued_cmd *qc)
120231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
120331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = qc->ap->private_data;
1204972c26bdd6b58e7534473c4f7928584578cf43f4Jeff Garzik	struct scatterlist *sg;
12053be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	struct mv_sg *mv_sg, *last_sg = NULL;
1206ff2aeb1eb64c8a4770a6304f9addbae9f9828646Tejun Heo	unsigned int si;
120731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1208eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	mv_sg = pp->sg_tbl[qc->tag];
1209ff2aeb1eb64c8a4770a6304f9addbae9f9828646Tejun Heo	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1210d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		dma_addr_t addr = sg_dma_address(sg);
1211d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		u32 sg_len = sg_dma_len(sg);
121222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
12134007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		while (sg_len) {
12144007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 offset = addr & 0xffff;
12154007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			u32 len = sg_len;
121622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
12174007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			if ((offset + sg_len > 0x10000))
12184007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson				len = 0x10000 - offset;
12194007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
12204007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
12214007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
12226c08772e49622e90d39903e7ff0be1a0f463ac86Jeff Garzik			mv_sg->flags_size = cpu_to_le32(len & 0xffff);
12234007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
12244007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			sg_len -= len;
12254007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			addr += len;
12264007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson
12273be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik			last_sg = mv_sg;
12284007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson			mv_sg++;
12294007b493ee6e4a52c2b618ab8361847fba5bf116Olof Johansson		}
123031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
12313be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik
12323be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik	if (likely(last_sg))
12333be6cbd73f74b4a3da82cc7d6e1688a4ae595fc7Jeff Garzik		last_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
123431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
123531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
12365796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
123731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1238559eedad7f7764dacca33980127b4615011230e4Mark Lord	u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
123931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		(last ? CRQB_CMD_LAST : 0);
1240559eedad7f7764dacca33980127b4615011230e4Mark Lord	*cmdw = cpu_to_le16(tmp);
124131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
124231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
124305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
124405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_prep - Host specific command preparation.
124505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to prepare
124605b308e1df6d9d673daedb517969241f41278b52Brett Russ *
124705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
124805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it handles prep of the CRQB
124905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      (command request block), does some sanity checking, and calls
125005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the SG load routine.
125105b308e1df6d9d673daedb517969241f41278b52Brett Russ *
125205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
125305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
125405b308e1df6d9d673daedb517969241f41278b52Brett Russ */
125531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_qc_prep(struct ata_queued_cmd *qc)
125631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
125731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_port *ap = qc->ap;
125831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct mv_port_priv *pp = ap->private_data;
1259e14698745dd0de1ddbf5cd0cca4313a90f8c1cc1Mark Lord	__le16 *cw;
126031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	struct ata_taskfile *tf;
126131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	u16 flags = 0;
1262a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
126331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1264138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	if ((qc->tf.protocol != ATA_PROT_DMA) &&
1265138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	    (qc->tf.protocol != ATA_PROT_NCQ))
126631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
126720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
126831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Fill in command request block
126931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
1270e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
127131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		flags |= CRQB_FLAG_READ;
1272beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
127331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	flags |= qc->tag << CRQB_TAG_SHIFT;
127431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1275bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1276bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1277a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1278a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr =
1279eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
1280a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].sg_addr_hi =
1281eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord		cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
1282a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
128331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1284a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	cw = &pp->crqb[in_index].ata_cmd[0];
128531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	tf = &qc->tf;
128631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
128731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Sadly, the CRQB cannot accomodate all registers--there are
128831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * only 11 bytes...so we must pick and choose required
128931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * registers based on the command.  So, we drop feature and
129031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * hob_feature for [RW] DMA commands, but they are needed for
129131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * NCQ.  NCQ will drop hob_nsect.
129220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
129331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	switch (tf->command) {
129431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ:
129531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_READ_EXT:
129631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE:
129731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_WRITE_EXT:
1298c15d85c8f3f73b5f20aae7928e25b6996f16b328Jens Axboe	case ATA_CMD_WRITE_FUA_EXT:
129931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
130031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
130131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_READ:
130231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	case ATA_CMD_FPDMA_WRITE:
13038b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
130431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
130531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
130631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	default:
130731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* The only other commands EDMA supports in non-queued and
130831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
130931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * of which are defined/used by Linux.  If we get here, this
131031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * driver needs work.
131131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 *
131231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * FIXME: modify libata to give qc_prep a return value and
131331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * return error here.
131431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
131531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		BUG_ON(tf->command);
131631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		break;
131731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
131831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
131931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
132031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
132131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
132231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
132331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
132431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
132531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
132631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
132731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1328e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1329e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1330e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	mv_fill_sg(qc);
1331e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik}
1332e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1333e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik/**
1334e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      mv_qc_prep_iie - Host specific command preparation.
1335e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      @qc: queued command to prepare
1336e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1337e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      This routine simply redirects to the general purpose routine
1338e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      if command is not DMA.  Else, it handles prep of the CRQB
1339e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      (command request block), does some sanity checking, and calls
1340e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      the SG load routine.
1341e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *
1342e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      LOCKING:
1343e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik *      Inherited from caller.
1344e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik */
1345e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzikstatic void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1346e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik{
1347e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_port *ap = qc->ap;
1348e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_port_priv *pp = ap->private_data;
1349e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct mv_crqb_iie *crqb;
1350e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	struct ata_taskfile *tf;
1351a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	unsigned in_index;
1352e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	u32 flags = 0;
1353e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1354138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	if ((qc->tf.protocol != ATA_PROT_DMA) &&
1355138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	    (qc->tf.protocol != ATA_PROT_NCQ))
1356e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		return;
1357e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1358e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* Fill in Gen IIE command request block
1359e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	 */
1360e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1361e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		flags |= CRQB_FLAG_READ;
1362e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1363beec7dbc6ff003bbc94de62b3323519c878fb2acTejun Heo	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1364e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	flags |= qc->tag << CRQB_TAG_SHIFT;
13658c0aeb4a483334613336ef895f34cecc0ecbbfa6Mark Lord	flags |= qc->tag << CRQB_HOSTQ_SHIFT;
1366e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1367bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get current queue index from software */
1368bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
1369a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord
1370a6432436c5e14b416f27c8f87c5bf0bc36771f49Mark Lord	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
1371eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
1372eb73d558d1c1c931de0b3a86af962c77d74ef688Mark Lord	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
1373e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->flags = cpu_to_le32(flags);
1374e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1375e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	tf = &qc->tf;
1376e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[0] = cpu_to_le32(
1377e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->command << 16) |
1378e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->feature << 24)
1379e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1380e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[1] = cpu_to_le32(
1381e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbal << 0) |
1382e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbam << 8) |
1383e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->lbah << 16) |
1384e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->device << 24)
1385e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1386e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[2] = cpu_to_le32(
1387e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbal << 0) |
1388e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbam << 8) |
1389e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_lbah << 16) |
1390e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_feature << 24)
1391e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1392e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	crqb->ata_cmd[3] = cpu_to_le32(
1393e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->nsect << 0) |
1394e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			(tf->hob_nsect << 8)
1395e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		);
1396e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
1397e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
139831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return;
139931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_fill_sg(qc);
140031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
140131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
140205b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
140305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_qc_issue - Initiate a command to the host
140405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @qc: queued command to start
140505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
140605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      This routine simply redirects to the general purpose routine
140705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if command is not DMA.  Else, it sanity checks our local
140805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      caches of the request producer/consumer indices then enables
140905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      DMA and bumps the request producer index.
141005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
141105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
141205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
141305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
14149a3d9eb0177eb10500d49cd283b35576082a522dTejun Heostatic unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
141531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
1416c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct ata_port *ap = qc->ap;
1417c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1418c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 in_index;
142031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1421138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	if ((qc->tf.protocol != ATA_PROT_DMA) &&
1422138bfdd03f2c08cc62b6af3900fb7be1c696315bMark Lord	    (qc->tf.protocol != ATA_PROT_NCQ)) {
142331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* We're about to send a non-EDMA capable command to the
142431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * port.  Turn off EDMA so there won't be problems accessing
142531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 * shadow block, etc registers.
142631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		 */
14270ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		__mv_stop_dma(ap);
142831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		return ata_qc_issue_prot(qc);
142931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	}
143031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1431721091685f853ba4e6c49f26f989db0b1a811250Mark Lord	mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
1432bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1433bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	pp->req_idx++;
143431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
1435bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
143631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
143731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* and write the request in pointer to kick the EDMA to life */
1438bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
1439bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
144031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
144131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	return 0;
144231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
144331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
144405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
144505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_err_intr - Handle error interrupts on the port
144605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
14479b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord *      @reset_allowed: bool: 0 == don't trigger from reset here
144805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
144905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      In most cases, just clear the interrupt and move on.  However,
145005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      some cases require an eDMA reset, which is done right before
145105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      the COMRESET in mv_phy_reset().  The SERR case requires a
145205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      clear of pending errors in the SATA SERROR register.  Finally,
145305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      if the port disabled DMA, update our cached copy to match.
145405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
145505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
145605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
145705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1458bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
145931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
146031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
1461bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 edma_err_cause, eh_freeze_mask, serr = 0;
1462bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1463bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1464bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
1465bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int action = 0, err_mask = 0;
14669af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_eh_info *ehi = &ap->link.eh_info;
146720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1468bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_clear_desc(ehi);
146920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1470bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!edma_enabled) {
1471bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* just a guess: do we need to do this? should we
1472bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * expand this, and do it in all cases?
1473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1474936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_read(&ap->link, SCR_ERROR, &serr);
1475936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
147620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1477bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1478bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1479bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1480bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
1481bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1482bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/*
1483bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * all generations share these EDMA error cause bits
1484bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
1485bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1486bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & EDMA_ERR_DEV)
1487bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_DEV;
1488bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
14896c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
1490bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			EDMA_ERR_INTRL_PAR)) {
1491bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask |= AC_ERR_ATA_BUS;
1492cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo		action |= ATA_EH_RESET;
1493b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo		ata_ehi_push_desc(ehi, "parity error");
1494bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1495bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
1496bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_hotplugged(ehi);
1497bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
1498b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			"dev disconnect" : "dev connect");
1499cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo		action |= ATA_EH_RESET;
1500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1502ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv)) {
1503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE_5;
1504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
15065ab063e397d9f6fcadb37a07465efcc87f9e9345Harvey Harrison			pp = ap->private_data;
1507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1508b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1510bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	} else {
1511bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		eh_freeze_mask = EDMA_EH_FREEZE;
1512bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1513bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
15145ab063e397d9f6fcadb37a07465efcc87f9e9345Harvey Harrison			pp = ap->private_data;
1515bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
1516b64bbc39f2122a2276578e40144af69ef01decd4Tejun Heo			ata_ehi_push_desc(ehi, "EDMA self-disable");
1517bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1518bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1519bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (edma_err_cause & EDMA_ERR_SERR) {
1520936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo			sata_scr_read(&ap->link, SCR_ERROR, &serr);
1521936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo			sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
1522bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_ATA_BUS;
1523cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo			action |= ATA_EH_RESET;
1524bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1525afb0edd922c7ed6e73678730921dfcccebec17e8Brett Russ	}
152620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
152720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* Clear EDMA now that SERR cleanup done */
15283606a380692cf958355a40fc1aa336800c17baf1Mark Lord	writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
152920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1530bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!err_mask) {
1531bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		err_mask = AC_ERR_OTHER;
1532cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo		action |= ATA_EH_RESET;
1533bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1534bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1535bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->serror |= serr;
1536bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ehi->action |= action;
1537bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1538bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc)
1539bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		qc->err_mask |= err_mask;
1540bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1541bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ehi->err_mask |= err_mask;
1542bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1543bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (edma_err_cause & eh_freeze_mask)
1544bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_freeze(ap);
1545bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	else
1546bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ata_port_abort(ap);
1547bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1548bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1549bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_pio(struct ata_port *ap)
1550bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1551bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1552bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u8 ata_status;
1553bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1554bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* ignore spurious intr if drive still BUSY */
1555bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_status = readb(ap->ioaddr.status_addr);
1556bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(ata_status & ATA_BUSY))
1557bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1558bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1559bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get active ATA command */
15609af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	qc = ata_qc_from_tag(ap, ap->link.active_tag);
1561bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (unlikely(!qc))			/* no active tag */
1562bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1563bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (qc->tf.flags & ATA_TFLAG_POLLING)	/* polling; we don't own qc */
1564bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1565bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1566bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* and finally, complete the ATA command */
1567bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	qc->err_mask |= ac_err_mask(ata_status);
1568bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_qc_complete(qc);
1569bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1570bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1571bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_intr_edma(struct ata_port *ap)
1572bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
1573bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
1574bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
1575bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp = ap->private_data;
1576bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1577bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 out_index, in_index;
1578bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	bool work_done = false;
1579bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1580bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* get h/w response queue pointer */
1581bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1582bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1583bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1584bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	while (1) {
1585bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		u16 status;
15866c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		unsigned int tag;
1587bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1588bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* get s/w response queue last-read pointer, and compare */
1589bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
1590bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (in_index == out_index)
1591bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
1592bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1593bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* 50xx: get active ATA command */
15940ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		if (IS_GEN_I(hpriv))
15959af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			tag = ap->link.active_tag;
1596bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
15976c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		/* Gen II/IIE: get active ATA command via tag, to enable
15986c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * support for queueing.  this works transparently for
15996c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		 * queued and non-queued modes.
1600bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
16018c0aeb4a483334613336ef895f34cecc0ecbbfa6Mark Lord		else
16028c0aeb4a483334613336ef895f34cecc0ecbbfa6Mark Lord			tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
1603bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
16046c1153e00af8de755ec278d873a97c9ce2a72d10Jeff Garzik		qc = ata_qc_from_tag(ap, tag);
1605bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1606cb92441973ebd71d556fc7cdd9e597582327dd71Mark Lord		/* For non-NCQ mode, the lower 8 bits of status
1607cb92441973ebd71d556fc7cdd9e597582327dd71Mark Lord		 * are from EDMA_ERR_IRQ_CAUSE_OFS,
1608cb92441973ebd71d556fc7cdd9e597582327dd71Mark Lord		 * which should be zero if all went well.
1609bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1610bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		status = le16_to_cpu(pp->crpb[out_index].flags);
1611cb92441973ebd71d556fc7cdd9e597582327dd71Mark Lord		if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
1612bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1613bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			return;
1614bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1615bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1616bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		/* and finally, complete the ATA command */
1617bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (qc) {
1618bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			qc->err_mask |=
1619bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
1620bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_qc_complete(qc);
1621bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1622bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
16230ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik		/* advance software response queue pointer, to
1624bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * indicate (after the loop completes) to hardware
1625bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 * that we have consumed a response queue entry.
1626bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		 */
1627bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		work_done = true;
1628bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->resp_idx++;
1629bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1630bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1631bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (work_done)
1632bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
1633bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 (out_index << EDMA_RSP_Q_PTR_SHIFT),
1634bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
163520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
163620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
163705b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
163805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_host_intr - Handle all interrupts on the given host controller
1639cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      @host: host specific structure
164005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @relevant: port error bits relevant to this host controller
164105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @hc: which host controller we're to look at
164205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
164305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read then write clear the HC interrupt status then walk each
164405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port connected to the HC and see if it needs servicing.  Port
164505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      success ints are reported in the HC interrupt status reg, the
164605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      port error ints are reported in the higher level main
164705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt status register and thus are passed in via the
164805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      'relevant' argument.
164905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
165005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
165105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
165205b308e1df6d9d673daedb517969241f41278b52Brett Russ */
1653cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzikstatic void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
165420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
1655f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = host->private_data;
1656f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
165720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
165820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	u32 hc_irq_cause;
1659f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	int port, port0, last_port;
166020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1661351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	if (hc == 0)
166220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = 0;
1663351772658a4d1acc0221a6e30676bb0594e74812Jeff Garzik	else
166420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		port0 = MV_PORTS_PER_HC;
166520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1666f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (HAS_PCI(host))
1667f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		last_port = port0 + MV_PORTS_PER_HC;
1668f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	else
1669f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		last_port = port0 + hpriv->n_ports;
167020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* we'll need the HC success int register in most cases */
167120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
1672bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (!hc_irq_cause)
1673bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
1674bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1675bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
167620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
167720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
16782dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		hc, relevant, hc_irq_cause);
167920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
16808f71efe25f8718200027b547a3e749ae3300fe60Yinghai Lu	for (port = port0; port < last_port; port++) {
1681cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		struct ata_port *ap = host->ports[port];
16828f71efe25f8718200027b547a3e749ae3300fe60Yinghai Lu		struct mv_port_priv *pp;
1683bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		int have_err_bits, hard_port, shift;
168455d8ca4f8094246da6e71889a4e04bfafaa78b10Jeff Garzik
1685bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
1686a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik			continue;
1687a2c91a8819e315e9fd1aef3ff57badb6c1be3f80Jeff Garzik
16888f71efe25f8718200027b547a3e749ae3300fe60Yinghai Lu		pp = ap->private_data;
16898f71efe25f8718200027b547a3e749ae3300fe60Yinghai Lu
169031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		shift = port << 1;		/* (port * 2) */
169120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (port >= MV_PORTS_PER_HC) {
169220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ			shift++;	/* skip bit 8 in the HC Main IRQ reg */
169320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
1694bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		have_err_bits = ((PORT0_ERR << shift) & relevant);
1695bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1696bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (unlikely(have_err_bits)) {
1697bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			struct ata_queued_cmd *qc;
16988b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik
16999af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1700bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
1701bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				continue;
1702bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1703bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			mv_err_intr(ap, qc);
1704bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			continue;
1705bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1706bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1707bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hard_port = mv_hardport_from_port(port); /* range 0..3 */
1708bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1709bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1710bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
1711bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_edma(ap);
1712bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		} else {
1713bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if ((DEV_IRQ << hard_port) & hc_irq_cause)
1714bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				mv_intr_pio(ap);
171520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
171620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
171720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("EXIT\n");
171820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
171920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1720bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_pci_error(struct ata_host *host, void __iomem *mmio)
1721bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
172202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_host_priv *hpriv = host->private_data;
1723bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_port *ap;
1724bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_queued_cmd *qc;
1725bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct ata_eh_info *ehi;
1726bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int i, err_mask, printed = 0;
1727bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 err_cause;
1728bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
172902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	err_cause = readl(mmio + hpriv->irq_cause_ofs);
1730bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1731bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
1732bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		   err_cause);
1733bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1734bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	DPRINTK("All regs @ PCI error\n");
1735bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1736bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
173702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	writelfl(0, mmio + hpriv->irq_cause_ofs);
1738bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1739bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	for (i = 0; i < host->n_ports; i++) {
1740bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		ap = host->ports[i];
1741936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		if (!ata_link_offline(&ap->link)) {
17429af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			ehi = &ap->link.eh_info;
1743bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_ehi_clear_desc(ehi);
1744bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (!printed++)
1745bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ata_ehi_push_desc(ehi,
1746bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik					"PCI err cause 0x%08x", err_cause);
1747bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			err_mask = AC_ERR_HOST_BUS;
1748cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo			ehi->action = ATA_EH_RESET;
17499af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo			qc = ata_qc_from_tag(ap, ap->link.active_tag);
1750bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			if (qc)
1751bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				qc->err_mask |= err_mask;
1752bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			else
1753bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik				ehi->err_mask |= err_mask;
1754bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
1755bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			ata_port_freeze(ap);
1756bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		}
1757bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1758bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
1759bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
176005b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
1761c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik *      mv_interrupt - Main interrupt event handler
176205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @irq: unused
176305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @dev_instance: private data; in this case the host structure
176405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
176505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Read the read only register to determine if any host
176605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      controllers have pending interrupts.  If so, call lower level
176705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      routine to handle.  Also check for PCI errors which are only
176805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      reported here.
176905b308e1df6d9d673daedb517969241f41278b52Brett Russ *
17708b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik *      LOCKING:
1771cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik *      This routine holds the host lock while processing pending
177205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts.
177305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
17747d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mv_interrupt(int irq, void *dev_instance)
177520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
1776cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
1777f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = host->private_data;
177820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int hc, handled = 0, n_hcs;
1779f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
1780646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	u32 irq_stat, irq_mask;
178120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1782646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	spin_lock(&host->lock);
1783f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
1784f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	irq_stat = readl(hpriv->main_cause_reg_addr);
1785f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	irq_mask = readl(hpriv->main_mask_reg_addr);
178620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
178720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* check the cases where we either have nothing pending or have read
178820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 * a bogus register value which can indicate HW removal or PCI fault
178920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	 */
1790646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
1791646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord		goto out_unlock;
179220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1793cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	n_hcs = mv_get_hc_count(host->ports[0]->flags);
179420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
17957bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
1796bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		mv_pci_error(host, mmio);
1797bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		handled = 1;
1798bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		goto out_unlock;	/* skip all other HC irq handling */
1799bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
1800bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
180120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hcs; hc++) {
180220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
180320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		if (relevant) {
1804cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik			mv_host_intr(host, relevant, hc);
1805bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			handled = 1;
180620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		}
180720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
1808615ab95342f6245026d8974b9724f7ea57d9a184Mark Lord
1809bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikout_unlock:
1810cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
181120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
181220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	return IRQ_RETVAL(handled);
181320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
181420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
1815c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1816c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1817c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1818c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1819c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1820c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return hc_mmio + ofs;
1821c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1822c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1823c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1824c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1825c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs;
1826c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1827c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	switch (sc_reg_in) {
1828c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_STATUS:
1829c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_ERROR:
1830c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	case SCR_CONTROL:
1831c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = sc_reg_in * sizeof(u32);
1832c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1833c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	default:
1834c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		ofs = 0xffffffffU;
1835c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		break;
1836c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1837c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return ofs;
1838c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1839c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1840da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
1841c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1842f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = ap->host->private_data;
1843f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
18440d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1845c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1846c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1847da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
1848da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(addr + ofs);
1849da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1850da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1851da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1852c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1853c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1854da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heostatic int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1855c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1856f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = ap->host->private_data;
1857f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
18580d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
1859c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int ofs = mv5_scr_offset(sc_reg_in);
1860c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1861da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (ofs != 0xffffffffU) {
18620d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writelfl(val, addr + ofs);
1863da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
1864da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	} else
1865da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
1866c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1867c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
18687bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
1869522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
18707bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	struct pci_dev *pdev = to_pci_dev(host->dev);
1871522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	int early_5080;
1872522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
187344c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
1874522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1875522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	if (!early_5080) {
1876522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1877522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		tmp |= (1 << 0);
1878522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1879522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	}
1880522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
18817bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	mv_reset_pci_bus(host, mmio);
1882522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1883522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1884522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzikstatic void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1885522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik{
1886522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1887522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik}
1888522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
188947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
1890ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
1891ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1892c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1893c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1894c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1895c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1896c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1897c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].pre = tmp & 0x1800;	/* bits 12:11 */
1898c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->signal[idx].amps = tmp & 0xe0;	/* bits 7:5 */
1899ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1900ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
190147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
1902ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
1903522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	u32 tmp;
1904522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1905522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(0, mmio + MV_GPIO_PORT_CTL);
1906522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1907522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1908522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik
1909522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1910522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	tmp |= ~(1 << 0);
1911522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1912ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
1913ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
19142a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzikstatic void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
19152a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
1916bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
1917c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1918c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1919c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1920c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1921c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1922c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	if (fix_apm_sq) {
1923c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_LT_MODE);
1924c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= (1 << 19);
1925c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_LT_MODE);
1926c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1927c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp = readl(phy_mmio + MV5_PHY_CTL);
1928c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp &= ~0x3;
1929c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		tmp |= 0x1;
1930c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writel(tmp, phy_mmio + MV5_PHY_CTL);
1931c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1932c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1933c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(phy_mmio + MV5_PHY_MODE);
1934c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= ~mask;
1935c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].pre;
1936c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= hpriv->signal[port].amps;
1937c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, phy_mmio + MV5_PHY_MODE);
1938bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
1939bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
1940c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1941c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1942c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, port_mmio + (reg))
1943c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1944c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port)
1945c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1946c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
1947c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1948c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1949c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1950c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	mv_channel_reset(hpriv, mmio, port);
1951c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1952c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x028);	/* command */
1953c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0x11f, port_mmio + EDMA_CFG_OFS);
1954c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x004);	/* timer */
1955c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x008);	/* irq err cause */
1956c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);	/* irq err mask */
1957c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);	/* rq bah */
1958c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);	/* rq inp */
1959c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);	/* rq outp */
1960c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x01c);	/* respq bah */
1961c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x024);	/* respq outp */
1962c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x020);	/* respq inp */
1963c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x02c);	/* test control */
1964c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1965c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1966c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1967c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1968c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#define ZERO(reg) writel(0, hc_mmio + (reg))
1969c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1970c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int hc)
197147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik{
1972c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1973c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	u32 tmp;
1974c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1975c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x00c);
1976c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x010);
1977c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x014);
1978c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	ZERO(0x018);
1979c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1980c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp = readl(hc_mmio + 0x20);
1981c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp &= 0x1c1c1c1c;
1982c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	tmp |= 0x03030303;
1983c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writel(tmp, hc_mmio + 0x20);
1984c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
1985c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik#undef ZERO
1986c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1987c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1988c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
1989c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
1990c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	unsigned int hc, port;
1991c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1992c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	for (hc = 0; hc < n_hc; hc++) {
1993c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		for (port = 0; port < MV_PORTS_PER_HC; port++)
1994c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			mv5_reset_hc_port(hpriv, mmio,
1995c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik					  (hc * MV_PORTS_PER_HC) + port);
1996c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
1997c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mv5_reset_one_hc(hpriv, mmio, hc);
1998c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
1999c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2000c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	return 0;
200147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik}
200247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
2003101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
2004101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#define ZERO(reg) writel(0, mmio + (reg))
20057bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
2006101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
200702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	struct mv_host_priv *hpriv = host->private_data;
2008101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
2009101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2010101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_PCI_MODE);
2011101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0xff00ffff;
2012101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_PCI_MODE);
2013101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2014101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_DISC_TIMER);
2015101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_MSI_TRIGGER);
2016101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
2017101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(HC_MAIN_IRQ_MASK_OFS);
2018101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_SERR_MASK);
201902a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	ZERO(hpriv->irq_cause_ofs);
202002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	ZERO(hpriv->irq_mask_ofs);
2021101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_LOW_ADDRESS);
2022101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_HIGH_ADDRESS);
2023101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_ATTRIBUTE);
2024101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	ZERO(MV_PCI_ERR_COMMAND);
2025101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2026101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik#undef ZERO
2027101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2028101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikstatic void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
2029101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
2030101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 tmp;
2031101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2032101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	mv5_reset_flash(hpriv, mmio);
2033101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2034101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp = readl(mmio + MV_GPIO_PORT_CTL);
2035101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp &= 0x3;
2036101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	tmp |= (1 << 5) | (1 << 6);
2037101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(tmp, mmio + MV_GPIO_PORT_CTL);
2038101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2039101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2040101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik/**
2041101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      mv6_reset_hc - Perform the 6xxx global soft reset
2042101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      @mmio: base address of the HBA
2043101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
2044101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      This routine only applies to 6xxx parts.
2045101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *
2046101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      LOCKING:
2047101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik *      Inherited from caller.
2048101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik */
2049c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
2050c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			unsigned int n_hc)
2051101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik{
2052101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
2053101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	int i, rc = 0;
2054101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	u32 t;
2055101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2056101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* Following procedure defined in PCI "main command and status
2057101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 * register" table.
2058101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	 */
2059101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	t = readl(reg);
2060101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	writel(t | STOP_PCI_MASTER, reg);
2061101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2062101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	for (i = 0; i < 1000; i++) {
2063101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2064101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
20652dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik		if (PCI_MASTER_EMPTY & t)
2066101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik			break;
2067101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2068101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(PCI_MASTER_EMPTY & t)) {
2069101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
2070101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2071101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2072101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2073101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2074101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* set reset */
2075101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2076101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2077101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t | GLOB_SFT_RST, reg);
2078101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2079101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2080101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
2081101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2082101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (!(GLOB_SFT_RST & t)) {
2083101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
2084101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2085101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		goto done;
2086101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2087101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2088101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
2089101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	i = 5;
2090101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	do {
2091101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
2092101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		t = readl(reg);
2093101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		udelay(1);
2094101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	} while ((GLOB_SFT_RST & t) && (i-- > 0));
2095101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
2096101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	if (GLOB_SFT_RST & t) {
2097101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
2098101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik		rc = 1;
2099101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	}
2100101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzikdone:
2101101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik	return rc;
2102101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik}
2103101ffae26c23ea928fce6d31a8b4901327d91a15Jeff Garzik
210447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
2105ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik			   void __iomem *mmio)
2106ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
2107ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	void __iomem *port_mmio;
2108ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	u32 tmp;
2109ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2110ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(mmio + MV_RESET_CFG);
2111ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	if ((tmp & (1 << 0)) == 0) {
211247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->signal[idx].amps = 0x7 << 8;
2113ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		hpriv->signal[idx].pre = 0x1 << 5;
2114ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik		return;
2115ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	}
2116ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2117ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	port_mmio = mv_port_base(mmio, idx);
2118ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	tmp = readl(port_mmio + PHY_MODE2);
2119ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2120ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
2121ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
2122ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2123ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
212447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzikstatic void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
2125ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik{
212647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
2127ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik}
2128ba3fe8fb6a469390a14379519915f3c39a973d99Jeff Garzik
2129c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
21302a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			   unsigned int port)
2131bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
2132c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port);
2133c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2134bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
213547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	int fix_phy_mode2 =
213647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
2137bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	int fix_phy_mode4 =
213847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
213947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	u32 m2, tmp;
214047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
214147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (fix_phy_mode2) {
214247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
214347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~(1 << 16);
214447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 |= (1 << 31);
214547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
214647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
214747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
214847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
214947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 = readl(port_mmio + PHY_MODE2);
215047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		m2 &= ~((1 << 16) | (1 << 31));
215147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		writel(m2, port_mmio + PHY_MODE2);
215247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
215347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		udelay(200);
215447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	}
215547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
215647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	/* who knows what this magic does */
215747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp = readl(port_mmio + PHY_MODE3);
215847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp &= ~0x7F800000;
215947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	tmp |= 0x2A800000;
216047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	writel(tmp, port_mmio + PHY_MODE3);
2161bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2162bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (fix_phy_mode4) {
216347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		u32 m4;
2164bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2165bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = readl(port_mmio + PHY_MODE4);
216647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
216747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
216847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			tmp = readl(port_mmio + 0x310);
2169bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2170bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		m4 = (m4 & ~(1 << 1)) | (1 << 0);
2171bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2172bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		writel(m4, port_mmio + PHY_MODE4);
217347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
217447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		if (hp_flags & MV_HP_ERRATA_60X1B2)
217547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			writel(tmp, port_mmio + 0x310);
2176bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2177bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2178bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	/* Revert values of pre-emphasis and signal amps to the saved ones */
2179bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 = readl(port_mmio + PHY_MODE2);
2180bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2181bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	m2 &= ~MV_M2_PREAMP_MASK;
21822a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].amps;
21832a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	m2 |= hpriv->signal[port].pre;
218447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	m2 &= ~(1 << 16);
2185bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2186e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	/* according to mvSata 3.6.1, some IIE values are fixed */
2187e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	if (IS_GEN_IIE(hpriv)) {
2188e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 &= ~0xC30FF01F;
2189e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		m2 |= 0x0000900F;
2190e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	}
2191e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2192bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	writel(m2, port_mmio + PHY_MODE2);
2193bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2194bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2195f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara/* TODO: use the generic LED interface to configure the SATA Presence */
2196f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara/* & Acitivy LEDs on the board */
2197f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_enable_leds(struct mv_host_priv *hpriv,
2198f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				      void __iomem *mmio)
2199f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2200f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return;
2201f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2202f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2203f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
2204f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			   void __iomem *mmio)
2205f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2206f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *port_mmio;
2207f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	u32 tmp;
2208f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2209f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	port_mmio = mv_port_base(mmio, idx);
2210f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	tmp = readl(port_mmio + PHY_MODE2);
2211f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2212f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->signal[idx].amps = tmp & 0x700;	/* bits 10:8 */
2213f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->signal[idx].pre = tmp & 0xe0;	/* bits 7:5 */
2214f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2215f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2216f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#undef ZERO
2217f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#define ZERO(reg) writel(0, port_mmio + (reg))
2218f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
2219f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara					void __iomem *mmio, unsigned int port)
2220f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2221f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *port_mmio = mv_port_base(mmio, port);
2222f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2223f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
2224f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2225f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	mv_channel_reset(hpriv, mmio, port);
2226f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2227f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x028);		/* command */
2228f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writel(0x101f, port_mmio + EDMA_CFG_OFS);
2229f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x004);		/* timer */
2230f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x008);		/* irq err cause */
2231f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x00c);		/* irq err mask */
2232f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x010);		/* rq bah */
2233f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x014);		/* rq inp */
2234f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x018);		/* rq outp */
2235f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x01c);		/* respq bah */
2236f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x024);		/* respq outp */
2237f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x020);		/* respq inp */
2238f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x02c);		/* test control */
2239f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
2240f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2241f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2242f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#undef ZERO
2243f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2244f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#define ZERO(reg) writel(0, hc_mmio + (reg))
2245f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_one_hc(struct mv_host_priv *hpriv,
2246f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				       void __iomem *mmio)
2247f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2248f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *hc_mmio = mv_hc_base(mmio, 0);
2249f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2250f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x00c);
2251f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x010);
2252f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ZERO(0x014);
2253f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2254f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2255f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2256f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#undef ZERO
2257f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2258f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_soc_reset_hc(struct mv_host_priv *hpriv,
2259f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				  void __iomem *mmio, unsigned int n_hc)
2260f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2261f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	unsigned int port;
2262f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2263f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	for (port = 0; port < hpriv->n_ports; port++)
2264f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		mv_soc_reset_hc_port(hpriv, mmio, port);
2265f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2266f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	mv_soc_reset_one_hc(hpriv, mmio);
2267f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2268f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return 0;
2269f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2270f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2271f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_flash(struct mv_host_priv *hpriv,
2272f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				      void __iomem *mmio)
2273f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2274f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return;
2275f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2276f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2277f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
2278f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2279f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return;
2280f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2281f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2282c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzikstatic void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
2283c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			     unsigned int port_no)
2284c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik{
2285c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	void __iomem *port_mmio = mv_port_base(mmio, port_no);
2286c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2287c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
2288c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2289ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv)) {
2290c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2291eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl |= (1 << 7);		/* enable gen2i speed */
2292eb46d684600ac145501805a294c94675e82eab2eMark Lord		ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
2293c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2294c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	}
2295c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2296c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	udelay(25);		/* allow reset propagation */
2297c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2298c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	/* Spec never mentions clearing the bit.  Marvell's driver does
2299c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 * clear the bit, however.
2300c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	 */
2301c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	writelfl(0, port_mmio + EDMA_CMD_OFS);
2302c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2303c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	hpriv->ops->phy_errata(hpriv, mmio, port_no);
2304c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
2305ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_I(hpriv))
2306c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		mdelay(1);
2307c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik}
2308c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
230905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
2310bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik *      mv_phy_reset - Perform eDMA reset followed by COMRESET
231105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ap: ATA channel to manipulate
231205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
231305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Part of this is taken from __sata_phy_reset and modified to
231405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      not sleep since this routine gets called from interrupt level.
231505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
231605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
231705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.  This is coded to safe to call at
231805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupt level, i.e. it does not sleep.
231931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ */
2320bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_phy_reset(struct ata_port *ap, unsigned int *class,
2321bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			 unsigned long deadline)
232220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
2323095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	struct mv_port_priv *pp	= ap->private_data;
2324cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
232520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	void __iomem *port_mmio = mv_ap_base(ap);
232622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	int retry = 5;
232722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	u32 sstatus;
232820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
232920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
233020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2331da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2332da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2333da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2334da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2335da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2336da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2337da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2338da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
23392d79ab8fd7a7bf3a45d0e948ae27b3dd95ce95eaSaeed Bishara			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2340da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2341da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
234220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
234322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* Issue COMRESET via SControl */
234422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzikcomreset_retry:
2345936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
2346bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(1);
234722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2348936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
2349bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	msleep(20);
235022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
235131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	do {
2352936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo		sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
235362f1d0e6de138b91d55fbd7d579c837ed62e9e31Andres Salomon		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
235431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			break;
235522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2356bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(1);
2357c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik	} while (time_before(jiffies, deadline));
235820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
235922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* work around errata */
2360ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik	if (IS_GEN_II(hpriv) &&
236122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
236222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	    (retry-- > 0))
236322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		goto comreset_retry;
2364095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2365da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#ifdef DEBUG
2366da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	{
2367da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		u32 sstatus, serror, scontrol;
2368da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
2369da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_STATUS, &sstatus);
2370da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_ERROR, &serror);
2371da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		mv_scr_read(ap, SCR_CONTROL, &scontrol);
2372da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
2373da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
2374da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
2375da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo#endif
237631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2377936fd7328657884d5a69a55666c74a55aa83ca27Tejun Heo	if (ata_link_offline(&ap->link)) {
2378bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		*class = ATA_DEV_NONE;
237920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return;
238020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
238120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
238222374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	/* even after SStatus reflects that device is ready,
238322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * it seems to take a while for link to be fully
238422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * established (and thus Status no longer 0x80/0x7F),
238522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 * so we poll a bit for that, here.
238622374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	 */
238722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	retry = 20;
238822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	while (1) {
238922374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		u8 drv_stat = ata_check_status(ap);
239022374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if ((drv_stat != 0x80) && (drv_stat != 0x7f))
239122374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2392bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		msleep(500);
239322374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik		if (retry-- <= 0)
239422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik			break;
2395bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		if (time_after(jiffies, deadline))
2396bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			break;
239722374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik	}
239822374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2399bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: if we passed the deadline, the following
2400bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 * code probably produces an invalid result
2401bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	 */
240220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2403bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* finally, read device signature from TF registers */
24043f19859ee95a38c066a0420eb8a30c76ecd67a42Tejun Heo	*class = ata_dev_try_classify(ap->link.device, 1, NULL);
2405095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2406095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2407095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2408bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
2409095fec887eaa1c38d17c0c929a6733c744a9fa1fJeff Garzik
2410bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	VPRINTK("EXIT\n");
241120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
241220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2413cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic int mv_prereset(struct ata_link *link, unsigned long deadline)
241422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik{
2415cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2416bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_port_priv *pp	= ap->private_data;
24170ea9e179f436f153fc19fdaef7abbc1e0da20762Jeff Garzik
2418cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo	mv_stop_dma(ap);
2419bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2420cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo	if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET))
2421bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
2422bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2423cf48062658e7ab3bc55e10c65676c3c73c16f8bfTejun Heo	return 0;
242422374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik}
242522374677d18c5eeefd3a283431d312b8c44fef02Jeff Garzik
2426cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic int mv_hardreset(struct ata_link *link, unsigned int *class,
2427bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik			unsigned long deadline)
242831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
2429cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2430bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	struct mv_host_priv *hpriv = ap->host->private_data;
2431f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
243231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2433bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_stop_dma(ap);
243431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2435bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_channel_reset(hpriv, mmio, ap->port_no);
243631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2437bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mv_phy_reset(ap, class, deadline);
2438bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2439bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	return 0;
2440bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2441bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2442cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heostatic void mv_postreset(struct ata_link *link, unsigned int *classes)
2443bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2444cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	struct ata_port *ap = link->ap;
2445bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 serr;
2446bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2447bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* print link status */
2448cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_print_link_status(link);
244931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2450bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear SError */
2451cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_scr_read(link, SCR_ERROR, &serr);
2452cc0680a580b5be81a1ca321b58f8e9b80b5c1052Tejun Heo	sata_scr_write_flush(link, SCR_ERROR, serr);
2453bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2454bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* bail out if no device is present */
2455bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
2456bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		DPRINTK("EXIT, no device\n");
2457bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		return;
24589b358e305c1d783c8a4ebf00344e95deb9e38f3dMark Lord	}
2459bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2460bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* set up device control */
2461bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
2462bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2463bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2464bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_error_handler(struct ata_port *ap)
2465bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2466bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	ata_do_eh(ap, mv_prereset, ata_std_softreset,
2467bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		  mv_hardreset, mv_postreset);
2468bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2469bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2470bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_freeze(struct ata_port *ap)
2471bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2472f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = ap->host->private_data;
2473bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2474bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask;
2475bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift;
2476bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2477bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2478bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2479bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2480bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0)
2481bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2482bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2483bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2484bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2485bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* disable assertion of portN err, done events */
2486f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	tmp = readl(hpriv->main_mask_reg_addr);
2487f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
2488bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik}
2489bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2490bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzikstatic void mv_eh_thaw(struct ata_port *ap)
2491bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik{
2492f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv = ap->host->private_data;
2493f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
2494bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2495bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2496bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	void __iomem *port_mmio = mv_ap_base(ap);
2497bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	u32 tmp, mask, hc_irq_cause;
2498bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	unsigned int shift, hc_port_no = ap->port_no;
2499bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2500bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* FIXME: handle coalescing completion events properly */
2501bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2502bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	shift = ap->port_no * 2;
2503bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	if (hc > 0) {
2504bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		shift++;
2505bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik		hc_port_no -= 4;
2506bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	}
2507bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2508bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	mask = 0x3 << shift;
2509bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2510bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear EDMA errors on this port */
2511bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2512bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2513bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* clear pending irq events */
2514bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
2515bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << hc_port_no);	/* clear CRPB-done */
2516bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
2517bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
2518bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik
2519bdd4dddee325a7dce3e84cf48201a06aa8508aa4Jeff Garzik	/* enable assertion of portN err, done events */
2520f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	tmp = readl(hpriv->main_mask_reg_addr);
2521f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writelfl(tmp | mask, hpriv->main_mask_reg_addr);
252231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
252331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
252405b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
252505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_port_init - Perform some early initialization on a single port.
252605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port: libata data structure storing shadow register addresses
252705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @port_mmio: base address of the port
252805b308e1df6d9d673daedb517969241f41278b52Brett Russ *
252905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Initialize shadow register mmio addresses, clear outstanding
253005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      interrupts on the port, and unmask interrupts for the future
253105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      start of the port.
253205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
253305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
253405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
253505b308e1df6d9d673daedb517969241f41278b52Brett Russ */
253631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russstatic void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
253720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
25380d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
253931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	unsigned serr_ofs;
254031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
25418b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	/* PIO related setup
254231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
254331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
25448b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->error_addr =
254531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
254631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
254731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
254831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
254931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
255031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
25518b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	port->status_addr =
255231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
255331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* special case: control/altstatus doesn't have ATA_REG_ address */
255431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
255531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
255631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* unused: */
25578d9db2d2fbae9e05022825c32f86e00c8e342860Randy Dunlap	port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
255820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
255931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Clear any currently outstanding port interrupt conditions */
256031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	serr_ofs = mv_scr_offset(SCR_ERROR);
256131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
256231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
256331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2564646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	/* unmask all non-transient EDMA error interrupts */
2565646a4da514f2555298481cb00dc5b3eb02b21b72Mark Lord	writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
256620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
25678b260248d9e0e8b64bb72fd4dee03ad86984c344Jeff Garzik	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
256831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_CFG_OFS),
256931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
257031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
257120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
257220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
25734447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_chip_id(struct ata_host *host, unsigned int board_idx)
2574bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik{
25754447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
25764447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2577bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	u32 hp_flags = hpriv->hp_flags;
2578bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
25795796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	switch (board_idx) {
258047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	case chip_5080:
258147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2582ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
258347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
258444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
258547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x1:
258647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
258747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
258847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
258947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
259047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
259147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
259247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
259347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying 50XXB2 workarounds to unknown rev\n");
259447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
259547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
259647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		}
259747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		break;
259847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
2599bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_504x:
2600bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_508x:
260147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv5xxx_ops;
2602ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_I;
2603bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
260444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
260547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x0:
260647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB0;
260747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
260847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x3:
260947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
261047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
261147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		default:
261247c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
261347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			   "Applying B2 workarounds to unknown rev\n");
261447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_50XXB2;
261547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
2616bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2617bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2618bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2619bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_604x:
2620bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	case chip_608x:
262147c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops = &mv6xxx_ops;
2622ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		hp_flags |= MV_HP_GEN_II;
262347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
262444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
262547c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x7:
262647c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
262747c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			break;
262847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		case 0x9:
262947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2630bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2631bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		default:
2632bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
263347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik				   "Applying B2 workarounds to unknown rev\n");
263447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik			hp_flags |= MV_HP_ERRATA_60X1B2;
2635bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik			break;
2636bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		}
2637bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		break;
2638bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2639e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_7042:
264002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hp_flags |= MV_HP_PCIE;
2641306b30f74d37f289033c696285e07ce0158a5d7bMark Lord		if (pdev->vendor == PCI_VENDOR_ID_TTI &&
2642306b30f74d37f289033c696285e07ce0158a5d7bMark Lord		    (pdev->device == 0x2300 || pdev->device == 0x2310))
2643306b30f74d37f289033c696285e07ce0158a5d7bMark Lord		{
26444e5200334e03e5620aa19d538300c13db270a063Mark Lord			/*
26454e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * Highpoint RocketRAID PCIe 23xx series cards:
26464e5200334e03e5620aa19d538300c13db270a063Mark Lord			 *
26474e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * Unconfigured drives are treated as "Legacy"
26484e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * by the BIOS, and it overwrites sector 8 with
26494e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * a "Lgcy" metadata block prior to Linux boot.
26504e5200334e03e5620aa19d538300c13db270a063Mark Lord			 *
26514e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * Configured drives (RAID or JBOD) leave sector 8
26524e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * alone, but instead overwrite a high numbered
26534e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * sector for the RAID metadata.  This sector can
26544e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * be determined exactly, by truncating the physical
26554e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * drive capacity to a nice even GB value.
26564e5200334e03e5620aa19d538300c13db270a063Mark Lord			 *
26574e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * RAID metadata is at: (dev->n_sectors & ~0xfffff)
26584e5200334e03e5620aa19d538300c13db270a063Mark Lord			 *
26594e5200334e03e5620aa19d538300c13db270a063Mark Lord			 * Warn the user, lest they think we're just buggy.
26604e5200334e03e5620aa19d538300c13db270a063Mark Lord			 */
26614e5200334e03e5620aa19d538300c13db270a063Mark Lord			printk(KERN_WARNING DRV_NAME ": Highpoint RocketRAID"
26624e5200334e03e5620aa19d538300c13db270a063Mark Lord				" BIOS CORRUPTS DATA on all attached drives,"
26634e5200334e03e5620aa19d538300c13db270a063Mark Lord				" regardless of if/how they are configured."
26644e5200334e03e5620aa19d538300c13db270a063Mark Lord				" BEWARE!\n");
26654e5200334e03e5620aa19d538300c13db270a063Mark Lord			printk(KERN_WARNING DRV_NAME ": For data safety, do not"
26664e5200334e03e5620aa19d538300c13db270a063Mark Lord				" use sectors 8-9 on \"Legacy\" drives,"
26674e5200334e03e5620aa19d538300c13db270a063Mark Lord				" and avoid the final two gigabytes on"
26684e5200334e03e5620aa19d538300c13db270a063Mark Lord				" all RocketRAID BIOS initialized drives.\n");
2669306b30f74d37f289033c696285e07ce0158a5d7bMark Lord		}
2670e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik	case chip_6042:
2671e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hpriv->ops = &mv6xxx_ops;
2672e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		hp_flags |= MV_HP_GEN_IIE;
2673e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
267444c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		switch (pdev->revision) {
2675e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x0:
2676e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_XX42A0;
2677e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2678e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		case 0x1:
2679e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2680e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2681e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		default:
2682e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			dev_printk(KERN_WARNING, &pdev->dev,
2683e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			   "Applying 60X1C0 workarounds to unknown rev\n");
2684e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			hp_flags |= MV_HP_ERRATA_60X1C0;
2685e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik			break;
2686e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		}
2687e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik		break;
2688f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	case chip_soc:
2689f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hpriv->ops = &mv_soc_ops;
2690f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hp_flags |= MV_HP_ERRATA_60X1C0;
2691f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		break;
2692e4e7b89280d1d666e2c09e5ad36cf071796c4c7eJeff Garzik
2693bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	default:
2694f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		dev_printk(KERN_ERR, host->dev,
26955796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik			   "BUG: invalid board index %u\n", board_idx);
2696bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik		return 1;
2697bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	}
2698bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2699bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	hpriv->hp_flags = hp_flags;
270002a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	if (hp_flags & MV_HP_PCIE) {
270102a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_cause_ofs	= PCIE_IRQ_CAUSE_OFS;
270202a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_mask_ofs	= PCIE_IRQ_MASK_OFS;
270302a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->unmask_all_irqs	= PCIE_UNMASK_ALL_IRQS;
270402a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	} else {
270502a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_cause_ofs	= PCI_IRQ_CAUSE_OFS;
270602a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->irq_mask_ofs	= PCI_IRQ_MASK_OFS;
270702a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord		hpriv->unmask_all_irqs	= PCI_UNMASK_ALL_IRQS;
270802a121da5a53d415b6596bc19cc6999d295d32a4Mark Lord	}
2709bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2710bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	return 0;
2711bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik}
2712bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
271305b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
271447c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik *      mv_init_host - Perform some early initialization of the host.
27154447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *	@host: ATA host to initialize
27164447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @board_idx: controller index
271705b308e1df6d9d673daedb517969241f41278b52Brett Russ *
271805b308e1df6d9d673daedb517969241f41278b52Brett Russ *      If possible, do an early global reset of the host.  Then do
271905b308e1df6d9d673daedb517969241f41278b52Brett Russ *      our port init and clear/unmask all/relevant host interrupts.
272005b308e1df6d9d673daedb517969241f41278b52Brett Russ *
272105b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
272205b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
272305b308e1df6d9d673daedb517969241f41278b52Brett Russ */
27244447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic int mv_init_host(struct ata_host *host, unsigned int board_idx)
272520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
272620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	int rc = 0, n_hc, port, hc;
27274447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
2728f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	void __iomem *mmio = hpriv->base;
272947c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik
27304447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_chip_id(host, board_idx);
2731bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik	if (rc)
2732f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	goto done;
2733f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2734f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (HAS_PCI(host)) {
2735f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hpriv->main_cause_reg_addr = hpriv->base +
2736f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		  HC_MAIN_IRQ_CAUSE_OFS;
2737f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
2738f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	} else {
2739f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hpriv->main_cause_reg_addr = hpriv->base +
2740f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		  HC_SOC_MAIN_IRQ_CAUSE_OFS;
2741f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		hpriv->main_mask_reg_addr = hpriv->base +
2742f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		  HC_SOC_MAIN_IRQ_MASK_OFS;
2743f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	}
2744f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	/* global interrupt mask */
2745f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	writel(0, hpriv->main_mask_reg_addr);
2746bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
27474447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_hc = mv_get_hc_count(host->ports[0]->flags);
2748bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
27494447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++)
275047c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik		hpriv->ops->read_preamp(hpriv, port, mmio);
275120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2752c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
275347c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	if (rc)
275420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		goto done;
275520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2756522479fb98c6667f081e75f87e298e413c0b1db8Jeff Garzik	hpriv->ops->reset_flash(hpriv, mmio);
27577bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	hpriv->ops->reset_bus(host, mmio);
275847c2b677daeed9c79ecb7167c211ff36876ea611Jeff Garzik	hpriv->ops->enable_leds(hpriv, mmio);
275920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
27604447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2761ee9ccdf70163ca6408f6965e0fbc65baeac7312cJeff Garzik		if (IS_GEN_II(hpriv)) {
2762c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik			void __iomem *port_mmio = mv_port_base(mmio, port);
2763c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik
27642a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
2765eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl |= (1 << 7);		/* enable gen2i speed */
2766eb46d684600ac145501805a294c94675e82eab2eMark Lord			ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
27672a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik			writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
27682a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		}
27692a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
2770c9d39130123238ac18478a42e25cb7996eacfcc0Jeff Garzik		hpriv->ops->phy_errata(hpriv, mmio, port);
27712a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik	}
27722a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik
27734447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (port = 0; port < host->n_ports; port++) {
2774cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		struct ata_port *ap = host->ports[port];
27752a47ce06d534692f9bd2bf4e90a20fc9b1054c39Jeff Garzik		void __iomem *port_mmio = mv_port_base(mmio, port);
2776cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
2777cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		mv_port_init(&ap->ioaddr, port_mmio);
2778cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
27797bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#ifdef CONFIG_PCI
2780f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		if (HAS_PCI(host)) {
2781f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			unsigned int offset = port_mmio - mmio;
2782f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
2783f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
2784f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		}
27857bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#endif
278620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
278720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
278820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	for (hc = 0; hc < n_hc; hc++) {
278931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
279031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
279131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
279231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			"(before clear)=0x%08x\n", hc,
279331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_CFG_OFS),
279431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
279531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
279631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		/* Clear any currently outstanding hc interrupt conditions */
279731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
279820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	}
279920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2800f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (HAS_PCI(host)) {
2801f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		/* Clear any currently outstanding host interrupt conditions */
2802f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		writelfl(0, mmio + hpriv->irq_cause_ofs);
280331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
2804f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		/* and unmask interrupt generation for host regs */
2805f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
2806f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		if (IS_GEN_I(hpriv))
2807f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			writelfl(~HC_MAIN_MASKED_IRQS_5,
2808f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				 hpriv->main_mask_reg_addr);
2809f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		else
2810f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			writelfl(~HC_MAIN_MASKED_IRQS,
2811f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				 hpriv->main_mask_reg_addr);
2812f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2813f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
2814f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			"PCI int cause/mask=0x%08x/0x%08x\n",
2815f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(hpriv->main_cause_reg_addr),
2816f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(hpriv->main_mask_reg_addr),
2817f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(mmio + hpriv->irq_cause_ofs),
2818f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(mmio + hpriv->irq_mask_ofs));
2819f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	} else {
2820f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		writelfl(~HC_MAIN_MASKED_IRQS_SOC,
2821f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			 hpriv->main_mask_reg_addr);
2822f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
2823f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(hpriv->main_cause_reg_addr),
2824f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			readl(hpriv->main_mask_reg_addr));
2825f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	}
2826f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharadone:
2827f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return rc;
2828f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2829fb621e2fde735abab854586d52c96c5624bcb5b8Jeff Garzik
2830fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradleystatic int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
2831fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley{
2832fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	hpriv->crqb_pool   = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ,
2833fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley							     MV_CRQB_Q_SZ, 0);
2834fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	if (!hpriv->crqb_pool)
2835fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley		return -ENOMEM;
2836fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley
2837fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	hpriv->crpb_pool   = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ,
2838fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley							     MV_CRPB_Q_SZ, 0);
2839fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	if (!hpriv->crpb_pool)
2840fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley		return -ENOMEM;
2841fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley
2842fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ,
2843fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley							     MV_SG_TBL_SZ, 0);
2844fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	if (!hpriv->sg_tbl_pool)
2845fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley		return -ENOMEM;
2846fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley
2847fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	return 0;
2848fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley}
2849fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley
2850f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara/**
2851f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      mv_platform_probe - handle a positive probe of an soc Marvell
2852f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      host
2853f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      @pdev: platform device found
2854f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *
2855f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      LOCKING:
2856f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      Inherited from caller.
2857f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara */
2858f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_platform_probe(struct platform_device *pdev)
2859f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2860f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	static int printed_version;
2861f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	const struct mv_sata_platform_data *mv_platform_data;
2862f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	const struct ata_port_info *ppi[] =
2863f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	    { &mv_port_info[chip_soc], NULL };
2864f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct ata_host *host;
2865f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct mv_host_priv *hpriv;
2866f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct resource *res;
2867f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	int n_ports, rc;
286820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2869f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (!printed_version++)
2870f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
2871bca1c4eb9411533d613123618c0d127fae532595Jeff Garzik
2872f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	/*
2873f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	 * Simple resource validation ..
2874f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	 */
2875f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (unlikely(pdev->num_resources != 2)) {
2876f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		dev_err(&pdev->dev, "invalid number of resources\n");
2877f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		return -EINVAL;
2878f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	}
2879f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2880f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	/*
2881f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	 * Get the register base first
2882f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	 */
2883f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2884f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (res == NULL)
2885f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		return -EINVAL;
2886f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2887f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	/* allocate host */
2888f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	mv_platform_data = pdev->dev.platform_data;
2889f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	n_ports = mv_platform_data->n_ports;
2890f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2891f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
2892f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
2893f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2894f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (!host || !hpriv)
2895f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		return -ENOMEM;
2896f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	host->private_data = hpriv;
2897f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->n_ports = n_ports;
2898f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2899f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	host->iomap = NULL;
2900f1cb0ea12fee23018ad1865bf789cbd463f13747Saeed Bishara	hpriv->base = devm_ioremap(&pdev->dev, res->start,
2901f1cb0ea12fee23018ad1865bf789cbd463f13747Saeed Bishara				   res->end - res->start + 1);
2902f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->base -= MV_SATAHC0_REG_BASE;
2903f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2904fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	rc = mv_create_dma_pools(hpriv, &pdev->dev);
2905fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley	if (rc)
2906fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley		return rc;
2907fbf14e2f2d674e6a2ff0fb2aa569e7f6687483a3Byron Bradley
2908f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	/* initialize adapter */
2909f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	rc = mv_init_host(host, chip_soc);
2910f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (rc)
2911f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		return rc;
2912f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2913f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	dev_printk(KERN_INFO, &pdev->dev,
2914f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		   "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
2915f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		   host->n_ports);
2916f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2917f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
2918f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				 IRQF_SHARED, &mv6_sht);
2919f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara}
2920f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2921f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara/*
2922f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *
2923f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      mv_platform_remove    -       unplug a platform interface
2924f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      @pdev: platform device
2925f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *
2926f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      A platform bus SATA device has been unplugged. Perform the needed
2927f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      cleanup. Also called on module unload for any active devices.
2928f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara */
2929f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int __devexit mv_platform_remove(struct platform_device *pdev)
2930f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara{
2931f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct device *dev = &pdev->dev;
2932f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	struct ata_host *host = dev_get_drvdata(dev);
2933f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2934f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	ata_host_detach(host);
2935f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	return 0;
293620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
293720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
2938f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic struct platform_driver mv_platform_driver = {
2939f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.probe			= mv_platform_probe,
2940f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.remove			= __devexit_p(mv_platform_remove),
2941f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.driver			= {
2942f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				   .name = DRV_NAME,
2943f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				   .owner = THIS_MODULE,
2944f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara				  },
2945f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara};
2946f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
2947f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
29487bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#ifdef CONFIG_PCI
2949f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_pci_init_one(struct pci_dev *pdev,
2950f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			   const struct pci_device_id *ent);
2951f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
29527bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29537bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic struct pci_driver mv_pci_driver = {
29547bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	.name			= DRV_NAME,
29557bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	.id_table		= mv_pci_tbl,
2956f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	.probe			= mv_pci_init_one,
29577bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	.remove			= ata_pci_remove_one,
29587bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara};
29597bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29607bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara/*
29617bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara * module options
29627bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara */
29637bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
29647bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29657bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29667bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara/* move to PCI layer or libata core? */
29677bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bisharastatic int pci_go_64(struct pci_dev *pdev)
29687bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara{
29697bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	int rc;
29707bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29717bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
29727bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
29737bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		if (rc) {
29747bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
29757bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			if (rc) {
29767bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara				dev_printk(KERN_ERR, &pdev->dev,
29777bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara					   "64-bit DMA enable failed\n");
29787bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara				return rc;
29797bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			}
29807bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		}
29817bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	} else {
29827bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
29837bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		if (rc) {
29847bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			dev_printk(KERN_ERR, &pdev->dev,
29857bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara				   "32-bit DMA enable failed\n");
29867bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			return rc;
29877bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		}
29887bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
29897bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		if (rc) {
29907bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			dev_printk(KERN_ERR, &pdev->dev,
29917bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara				   "32-bit consistent DMA enable failed\n");
29927bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara			return rc;
29937bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara		}
29947bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	}
29957bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
29967bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	return rc;
29977bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara}
29987bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara
299905b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
300005b308e1df6d9d673daedb517969241f41278b52Brett Russ *      mv_print_info - Dump key info to kernel log for perusal.
30014447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo *      @host: ATA host to print info about
300205b308e1df6d9d673daedb517969241f41278b52Brett Russ *
300305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      FIXME: complete this.
300405b308e1df6d9d673daedb517969241f41278b52Brett Russ *
300505b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
300605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
300705b308e1df6d9d673daedb517969241f41278b52Brett Russ */
30084447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic void mv_print_info(struct ata_host *host)
300931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ{
30104447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
30114447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv = host->private_data;
301244c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok	u8 scc;
3013c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	const char *scc_s, *gen;
301431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
301531961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Use this to determine the HW stepping of the chip so we know
301631961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 * what errata to workaround
301731961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	 */
301831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
301931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	if (scc == 0)
302031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "SCSI";
302131961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else if (scc == 0x01)
302231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		scc_s = "RAID";
302331961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	else
3024c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		scc_s = "?";
3025c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik
3026c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	if (IS_GEN_I(hpriv))
3027c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "I";
3028c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_II(hpriv))
3029c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "II";
3030c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else if (IS_GEN_IIE(hpriv))
3031c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "IIE";
3032c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	else
3033c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik		gen = "?";
303431961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
3035a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	dev_printk(KERN_INFO, &pdev->dev,
3036c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
3037c1e4fe711a410a139095e6b3e3ce3f07f466063cJeff Garzik	       gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
303831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
303931961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ}
304031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ
304105b308e1df6d9d673daedb517969241f41278b52Brett Russ/**
3042f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara *      mv_pci_init_one - handle a positive probe of a PCI Marvell host
304305b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @pdev: PCI device found
304405b308e1df6d9d673daedb517969241f41278b52Brett Russ *      @ent: PCI device ID entry for the matched host
304505b308e1df6d9d673daedb517969241f41278b52Brett Russ *
304605b308e1df6d9d673daedb517969241f41278b52Brett Russ *      LOCKING:
304705b308e1df6d9d673daedb517969241f41278b52Brett Russ *      Inherited from caller.
304805b308e1df6d9d673daedb517969241f41278b52Brett Russ */
3049f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_pci_init_one(struct pci_dev *pdev,
3050f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara			   const struct pci_device_id *ent)
305120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
30522dcb407e61458ded17503d6bd12b8c064965368bJeff Garzik	static int printed_version;
305320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	unsigned int board_idx = (unsigned int)ent->driver_data;
30544447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
30554447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
30564447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct mv_host_priv *hpriv;
30574447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int n_ports, rc;
305820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
3059a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik	if (!printed_version++)
3060a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
306120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
30624447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
30634447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
30644447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
30654447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
30664447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
30674447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host || !hpriv)
30684447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
30694447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->private_data = hpriv;
3070f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->n_ports = n_ports;
30714447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
30724447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* acquire resources */
307324dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
307424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
307520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ		return rc;
307620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
30770d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
30780d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
307924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
30800d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
308124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
30824447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
3083f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	hpriv->base = host->iomap[MV_PRIMARY_BAR];
308420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
3085d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	rc = pci_go_64(pdev);
3086d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik	if (rc)
3087d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik		return rc;
3088d88184fb2348a50f7c34f5d49a901c875b2e0114Jeff Garzik
3089da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	rc = mv_create_dma_pools(hpriv, &pdev->dev);
3090da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord	if (rc)
3091da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord		return rc;
3092da2fa9baf06f33a8fa7aa3f56c9f2b4070ceca0eMark Lord
309320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	/* initialize adapter */
30944447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	rc = mv_init_host(host, board_idx);
309524dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (rc)
309624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
309720f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
309831961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	/* Enable interrupts */
30996a59dcf8678cbc4106a8a6e158d7408a87691358Tejun Heo	if (msi && pci_enable_msi(pdev))
310031961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ		pci_intx(pdev, 1);
310120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
310231961943e3110c5a1c36b1e0069c29f7c4380e51Brett Russ	mv_dump_pci_cfg(pdev, 0x68);
31034447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mv_print_info(host);
310420f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
31054447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	pci_set_master(pdev);
3106ea8b4db97aa41a66c05daa4055a1974692ccd52dJeff Garzik	pci_try_set_mwi(pdev);
31074447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
3108c5d3e45a2200a0905dc45b72714726b7aac3aaf1Jeff Garzik				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
310920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
31107bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#endif
311120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
3112f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int mv_platform_probe(struct platform_device *pdev);
3113f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bisharastatic int __devexit mv_platform_remove(struct platform_device *pdev);
3114f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
311520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic int __init mv_init(void)
311620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
31177bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	int rc = -ENODEV;
31187bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#ifdef CONFIG_PCI
31197bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	rc = pci_register_driver(&mv_pci_driver);
3120f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (rc < 0)
3121f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		return rc;
3122f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#endif
3123f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	rc = platform_driver_register(&mv_platform_driver);
3124f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara
3125f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara#ifdef CONFIG_PCI
3126f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	if (rc < 0)
3127f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara		pci_unregister_driver(&mv_pci_driver);
31287bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#endif
31297bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara	return rc;
313020f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
313120f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
313220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russstatic void __exit mv_exit(void)
313320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ{
31347bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#ifdef CONFIG_PCI
313520f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ	pci_unregister_driver(&mv_pci_driver);
31367bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#endif
3137f351b2d638c3cb0b95adde3549b7bfaf3f991dfaSaeed Bishara	platform_driver_unregister(&mv_platform_driver);
313820f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ}
313920f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
314020f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_AUTHOR("Brett Russ");
314120f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
314220f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_LICENSE("GPL");
314320f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_DEVICE_TABLE(pci, mv_pci_tbl);
314420f733e7d75a16bffc34842b7682c9247dd5f954Brett RussMODULE_VERSION(DRV_VERSION);
31452e7e1214defe7783c8187962bacdd0a87a7dbeeeMartin MichlmayrMODULE_ALIAS("platform:sata_mv");
314620f733e7d75a16bffc34842b7682c9247dd5f954Brett Russ
31477bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#ifdef CONFIG_PCI
3148ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzikmodule_param(msi, int, 0444);
3149ddef9bb367b19383df627e388cb4c01c86ddba6cJeff GarzikMODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
31507bb3c5290ca0ec9e65947c907495c2b56e895e46Saeed Bishara#endif
3151ddef9bb367b19383df627e388cb4c01c86ddba6cJeff Garzik
315220f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_init(mv_init);
315320f733e7d75a16bffc34842b7682c9247dd5f954Brett Russmodule_exit(mv_exit);
3154