blob: b4b737e081e88a06342eb2f140d6e756e3bd71a6 [file] [log] [blame]
Brett Russ20f733e72005-09-01 18:26:17 -04001/*
2 * sata_mv.c - Marvell SATA support
3 *
Jeff Garzik8b260242005-11-12 12:32:50 -05004 * Copyright 2005: EMC Corporation, all rights reserved.
Jeff Garzike2b1be52005-11-18 14:04:23 -05005 * Copyright 2005 Red Hat, Inc. All rights reserved.
Brett Russ20f733e72005-09-01 18:26:17 -04006 *
7 * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
Jeff Garzik4a05e202007-05-24 23:40:15 -040024/*
25 sata_mv TODO list:
26
27 1) Needs a full errata audit for all chipsets. I implemented most
28 of the errata workarounds found in the Marvell vendor driver, but
29 I distinctly remember a couple workarounds (one related to PCI-X)
30 are still needed.
31
Jeff Garzik4a05e202007-05-24 23:40:15 -040032 4) Add NCQ support (easy to intermediate, once new-EH support appears)
33
34 5) Investigate problems with PCI Message Signalled Interrupts (MSI).
35
36 6) Add port multiplier support (intermediate)
37
Jeff Garzik4a05e202007-05-24 23:40:15 -040038 8) Develop a low-power-consumption strategy, and implement it.
39
40 9) [Experiment, low priority] See if ATAPI can be supported using
41 "unknown FIS" or "vendor-specific FIS" support, or something creative
42 like that.
43
44 10) [Experiment, low priority] Investigate interrupt coalescing.
45 Quite often, especially with PCI Message Signalled Interrupts (MSI),
46 the overhead reduced by interrupt mitigation is quite often not
47 worth the latency cost.
48
49 11) [Experiment, Marvell value added] Is it possible to use target
50 mode to cross-connect two Linux boxes with Marvell cards? If so,
51 creating LibATA target mode support would be very interesting.
52
53 Target mode, for those without docs, is the ability to directly
54 connect two SATA controllers.
55
56 13) Verify that 7042 is fully supported. I only have a 6042.
57
58*/
59
60
Brett Russ20f733e72005-09-01 18:26:17 -040061#include <linux/kernel.h>
62#include <linux/module.h>
63#include <linux/pci.h>
64#include <linux/init.h>
65#include <linux/blkdev.h>
66#include <linux/delay.h>
67#include <linux/interrupt.h>
Brett Russ20f733e72005-09-01 18:26:17 -040068#include <linux/dma-mapping.h>
Jeff Garzika9524a72005-10-30 14:39:11 -050069#include <linux/device.h>
Brett Russ20f733e72005-09-01 18:26:17 -040070#include <scsi/scsi_host.h>
Jeff Garzik193515d2005-11-07 00:59:37 -050071#include <scsi/scsi_cmnd.h>
Brett Russ20f733e72005-09-01 18:26:17 -040072#include <linux/libata.h>
Brett Russ20f733e72005-09-01 18:26:17 -040073
74#define DRV_NAME "sata_mv"
Jeff Garzik8bc3fc42007-05-21 20:26:38 -040075#define DRV_VERSION "0.81"
Brett Russ20f733e72005-09-01 18:26:17 -040076
77enum {
78 /* BAR's are enumerated in terms of pci_resource_start() terms */
79 MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
80 MV_IO_BAR = 2, /* offset 0x18: IO space */
81 MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
82
83 MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
84 MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
85
86 MV_PCI_REG_BASE = 0,
87 MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
Mark Lord615ab952006-05-19 16:24:56 -040088 MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
89 MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
90 MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
91 MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
92 MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
93
Brett Russ20f733e72005-09-01 18:26:17 -040094 MV_SATAHC0_REG_BASE = 0x20000,
Jeff Garzik522479f2005-11-12 22:14:02 -050095 MV_FLASH_CTL = 0x1046c,
Jeff Garzikbca1c4e2005-11-12 12:48:15 -050096 MV_GPIO_PORT_CTL = 0x104f0,
97 MV_RESET_CFG = 0x180d8,
Brett Russ20f733e72005-09-01 18:26:17 -040098
99 MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
100 MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
101 MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
102 MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
103
Brett Russ31961942005-09-30 01:36:00 -0400104 MV_MAX_Q_DEPTH = 32,
105 MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
106
107 /* CRQB needs alignment on a 1KB boundary. Size == 1KB
108 * CRPB needs alignment on a 256B boundary. Size == 256B
109 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
110 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
111 */
112 MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
113 MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
114 MV_MAX_SG_CT = 176,
115 MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
116 MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
117
Brett Russ20f733e72005-09-01 18:26:17 -0400118 MV_PORTS_PER_HC = 4,
119 /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
120 MV_PORT_HC_SHIFT = 2,
Brett Russ31961942005-09-30 01:36:00 -0400121 /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
Brett Russ20f733e72005-09-01 18:26:17 -0400122 MV_PORT_MASK = 3,
123
124 /* Host Flags */
125 MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
126 MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400127 MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400128 ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
129 ATA_FLAG_PIO_POLLING,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500130 MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
Brett Russ20f733e72005-09-01 18:26:17 -0400131
Brett Russ31961942005-09-30 01:36:00 -0400132 CRQB_FLAG_READ = (1 << 0),
133 CRQB_TAG_SHIFT = 1,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400134 CRQB_IOID_SHIFT = 6, /* CRQB Gen-II/IIE IO Id shift */
135 CRQB_HOSTQ_SHIFT = 17, /* CRQB Gen-II/IIE HostQueTag shift */
Brett Russ31961942005-09-30 01:36:00 -0400136 CRQB_CMD_ADDR_SHIFT = 8,
137 CRQB_CMD_CS = (0x2 << 11),
138 CRQB_CMD_LAST = (1 << 15),
139
140 CRPB_FLAG_STATUS_SHIFT = 8,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400141 CRPB_IOID_SHIFT_6 = 5, /* CRPB Gen-II IO Id shift */
142 CRPB_IOID_SHIFT_7 = 7, /* CRPB Gen-IIE IO Id shift */
Brett Russ31961942005-09-30 01:36:00 -0400143
144 EPRD_FLAG_END_OF_TBL = (1 << 31),
145
Brett Russ20f733e72005-09-01 18:26:17 -0400146 /* PCI interface registers */
147
Brett Russ31961942005-09-30 01:36:00 -0400148 PCI_COMMAND_OFS = 0xc00,
149
Brett Russ20f733e72005-09-01 18:26:17 -0400150 PCI_MAIN_CMD_STS_OFS = 0xd30,
151 STOP_PCI_MASTER = (1 << 2),
152 PCI_MASTER_EMPTY = (1 << 3),
153 GLOB_SFT_RST = (1 << 4),
154
Jeff Garzik522479f2005-11-12 22:14:02 -0500155 MV_PCI_MODE = 0xd00,
156 MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
157 MV_PCI_DISC_TIMER = 0xd04,
158 MV_PCI_MSI_TRIGGER = 0xc38,
159 MV_PCI_SERR_MASK = 0xc28,
160 MV_PCI_XBAR_TMOUT = 0x1d04,
161 MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
162 MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
163 MV_PCI_ERR_ATTRIBUTE = 0x1d48,
164 MV_PCI_ERR_COMMAND = 0x1d50,
165
166 PCI_IRQ_CAUSE_OFS = 0x1d58,
167 PCI_IRQ_MASK_OFS = 0x1d5c,
Brett Russ20f733e72005-09-01 18:26:17 -0400168 PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
169
170 HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
171 HC_MAIN_IRQ_MASK_OFS = 0x1d64,
172 PORT0_ERR = (1 << 0), /* shift by port # */
173 PORT0_DONE = (1 << 1), /* shift by port # */
174 HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
175 HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
176 PCI_ERR = (1 << 18),
177 TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
178 TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
Jeff Garzikfb621e22007-02-25 04:19:45 -0500179 PORTS_0_3_COAL_DONE = (1 << 8),
180 PORTS_4_7_COAL_DONE = (1 << 17),
Brett Russ20f733e72005-09-01 18:26:17 -0400181 PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
182 GPIO_INT = (1 << 22),
183 SELF_INT = (1 << 23),
184 TWSI_INT = (1 << 24),
185 HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
Jeff Garzikfb621e22007-02-25 04:19:45 -0500186 HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
Jeff Garzik8b260242005-11-12 12:32:50 -0500187 HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
Brett Russ20f733e72005-09-01 18:26:17 -0400188 PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
189 HC_MAIN_RSVD),
Jeff Garzikfb621e22007-02-25 04:19:45 -0500190 HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
191 HC_MAIN_RSVD_5),
Brett Russ20f733e72005-09-01 18:26:17 -0400192
193 /* SATAHC registers */
194 HC_CFG_OFS = 0,
195
196 HC_IRQ_CAUSE_OFS = 0x14,
Brett Russ31961942005-09-30 01:36:00 -0400197 CRPB_DMA_DONE = (1 << 0), /* shift by port # */
Brett Russ20f733e72005-09-01 18:26:17 -0400198 HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
199 DEV_IRQ = (1 << 8), /* shift by port # */
200
201 /* Shadow block registers */
Brett Russ31961942005-09-30 01:36:00 -0400202 SHD_BLK_OFS = 0x100,
203 SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
Brett Russ20f733e72005-09-01 18:26:17 -0400204
205 /* SATA registers */
206 SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
207 SATA_ACTIVE_OFS = 0x350,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500208 PHY_MODE3 = 0x310,
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500209 PHY_MODE4 = 0x314,
210 PHY_MODE2 = 0x330,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500211 MV5_PHY_MODE = 0x74,
212 MV5_LT_MODE = 0x30,
213 MV5_PHY_CTL = 0x0C,
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500214 SATA_INTERFACE_CTL = 0x050,
215
216 MV_M2_PREAMP_MASK = 0x7e0,
Brett Russ20f733e72005-09-01 18:26:17 -0400217
218 /* Port registers */
219 EDMA_CFG_OFS = 0,
Brett Russ31961942005-09-30 01:36:00 -0400220 EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
221 EDMA_CFG_NCQ = (1 << 5),
222 EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
223 EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
224 EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
Brett Russ20f733e72005-09-01 18:26:17 -0400225
226 EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
227 EDMA_ERR_IRQ_MASK_OFS = 0xc,
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400228 EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */
229 EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */
230 EDMA_ERR_DEV = (1 << 2), /* device error */
231 EDMA_ERR_DEV_DCON = (1 << 3), /* device disconnect */
232 EDMA_ERR_DEV_CON = (1 << 4), /* device connected */
233 EDMA_ERR_SERR = (1 << 5), /* SError bits [WBDST] raised */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400234 EDMA_ERR_SELF_DIS = (1 << 7), /* Gen II/IIE self-disable */
235 EDMA_ERR_SELF_DIS_5 = (1 << 8), /* Gen I self-disable */
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400236 EDMA_ERR_BIST_ASYNC = (1 << 8), /* BIST FIS or Async Notify */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400237 EDMA_ERR_TRANS_IRQ_7 = (1 << 8), /* Gen IIE transprt layer irq */
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400238 EDMA_ERR_CRQB_PAR = (1 << 9), /* CRQB parity error */
239 EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */
240 EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */
241 EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */
242 EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */
Brett Russ20f733e72005-09-01 18:26:17 -0400243 EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400244 EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */
245 EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */
246 EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */
247 EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400248 EDMA_ERR_OVERRUN_5 = (1 << 5),
249 EDMA_ERR_UNDERRUN_5 = (1 << 6),
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400250 EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
251 EDMA_ERR_PRD_PAR |
252 EDMA_ERR_DEV_DCON |
253 EDMA_ERR_DEV_CON |
254 EDMA_ERR_SERR |
255 EDMA_ERR_SELF_DIS |
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400256 EDMA_ERR_CRQB_PAR |
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400257 EDMA_ERR_CRPB_PAR |
258 EDMA_ERR_INTRL_PAR |
259 EDMA_ERR_IORDY |
260 EDMA_ERR_LNK_CTRL_RX_2 |
261 EDMA_ERR_LNK_DATA_RX |
262 EDMA_ERR_LNK_DATA_TX |
263 EDMA_ERR_TRANS_PROTO,
264 EDMA_EH_FREEZE_5 = EDMA_ERR_D_PAR |
265 EDMA_ERR_PRD_PAR |
266 EDMA_ERR_DEV_DCON |
267 EDMA_ERR_DEV_CON |
268 EDMA_ERR_OVERRUN_5 |
269 EDMA_ERR_UNDERRUN_5 |
270 EDMA_ERR_SELF_DIS_5 |
Jeff Garzik6c1153e2007-07-13 15:20:15 -0400271 EDMA_ERR_CRQB_PAR |
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400272 EDMA_ERR_CRPB_PAR |
273 EDMA_ERR_INTRL_PAR |
274 EDMA_ERR_IORDY,
Brett Russ20f733e72005-09-01 18:26:17 -0400275
Brett Russ31961942005-09-30 01:36:00 -0400276 EDMA_REQ_Q_BASE_HI_OFS = 0x10,
277 EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
Brett Russ31961942005-09-30 01:36:00 -0400278
279 EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
280 EDMA_REQ_Q_PTR_SHIFT = 5,
281
282 EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
283 EDMA_RSP_Q_IN_PTR_OFS = 0x20,
284 EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
Brett Russ31961942005-09-30 01:36:00 -0400285 EDMA_RSP_Q_PTR_SHIFT = 3,
286
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400287 EDMA_CMD_OFS = 0x28, /* EDMA command register */
288 EDMA_EN = (1 << 0), /* enable EDMA */
289 EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
290 ATA_RST = (1 << 2), /* reset trans/link/phy */
Brett Russ20f733e72005-09-01 18:26:17 -0400291
Jeff Garzikc9d39132005-11-13 17:47:51 -0500292 EDMA_IORDY_TMOUT = 0x34,
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500293 EDMA_ARB_CFG = 0x38,
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500294
Brett Russ31961942005-09-30 01:36:00 -0400295 /* Host private flags (hp_flags) */
296 MV_HP_FLAG_MSI = (1 << 0),
Jeff Garzik47c2b672005-11-12 21:13:17 -0500297 MV_HP_ERRATA_50XXB0 = (1 << 1),
298 MV_HP_ERRATA_50XXB2 = (1 << 2),
299 MV_HP_ERRATA_60X1B2 = (1 << 3),
300 MV_HP_ERRATA_60X1C0 = (1 << 4),
Jeff Garzike4e7b892006-01-31 12:18:41 -0500301 MV_HP_ERRATA_XX42A0 = (1 << 5),
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400302 MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
303 MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
304 MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
Brett Russ20f733e72005-09-01 18:26:17 -0400305
Brett Russ31961942005-09-30 01:36:00 -0400306 /* Port private flags (pp_flags) */
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400307 MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
308 MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */
Brett Russ31961942005-09-30 01:36:00 -0400309};
310
Jeff Garzikee9ccdf2007-07-12 15:51:22 -0400311#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
312#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
Jeff Garzike4e7b892006-01-31 12:18:41 -0500313#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500314
Jeff Garzik095fec82005-11-12 09:50:49 -0500315enum {
Jeff Garzikd88184f2007-02-26 01:26:06 -0500316 MV_DMA_BOUNDARY = 0xffffffffU,
Jeff Garzik095fec82005-11-12 09:50:49 -0500317
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400318 /* mask of register bits containing lower 32 bits
319 * of EDMA request queue DMA address
320 */
Jeff Garzik095fec82005-11-12 09:50:49 -0500321 EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
322
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400323 /* ditto, for response queue */
Jeff Garzik095fec82005-11-12 09:50:49 -0500324 EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
325};
326
Jeff Garzik522479f2005-11-12 22:14:02 -0500327enum chip_type {
328 chip_504x,
329 chip_508x,
330 chip_5080,
331 chip_604x,
332 chip_608x,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500333 chip_6042,
334 chip_7042,
Jeff Garzik522479f2005-11-12 22:14:02 -0500335};
336
Brett Russ31961942005-09-30 01:36:00 -0400337/* Command ReQuest Block: 32B */
338struct mv_crqb {
Mark Lorde1469872006-05-22 19:02:03 -0400339 __le32 sg_addr;
340 __le32 sg_addr_hi;
341 __le16 ctrl_flags;
342 __le16 ata_cmd[11];
Brett Russ31961942005-09-30 01:36:00 -0400343};
344
Jeff Garzike4e7b892006-01-31 12:18:41 -0500345struct mv_crqb_iie {
Mark Lorde1469872006-05-22 19:02:03 -0400346 __le32 addr;
347 __le32 addr_hi;
348 __le32 flags;
349 __le32 len;
350 __le32 ata_cmd[4];
Jeff Garzike4e7b892006-01-31 12:18:41 -0500351};
352
Brett Russ31961942005-09-30 01:36:00 -0400353/* Command ResPonse Block: 8B */
354struct mv_crpb {
Mark Lorde1469872006-05-22 19:02:03 -0400355 __le16 id;
356 __le16 flags;
357 __le32 tmstmp;
Brett Russ31961942005-09-30 01:36:00 -0400358};
359
360/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
361struct mv_sg {
Mark Lorde1469872006-05-22 19:02:03 -0400362 __le32 addr;
363 __le32 flags_size;
364 __le32 addr_hi;
365 __le32 reserved;
Brett Russ20f733e72005-09-01 18:26:17 -0400366};
367
368struct mv_port_priv {
Brett Russ31961942005-09-30 01:36:00 -0400369 struct mv_crqb *crqb;
370 dma_addr_t crqb_dma;
371 struct mv_crpb *crpb;
372 dma_addr_t crpb_dma;
373 struct mv_sg *sg_tbl;
374 dma_addr_t sg_tbl_dma;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400375
376 unsigned int req_idx;
377 unsigned int resp_idx;
378
Brett Russ31961942005-09-30 01:36:00 -0400379 u32 pp_flags;
Brett Russ20f733e72005-09-01 18:26:17 -0400380};
381
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500382struct mv_port_signal {
383 u32 amps;
384 u32 pre;
385};
386
Jeff Garzik47c2b672005-11-12 21:13:17 -0500387struct mv_host_priv;
388struct mv_hw_ops {
Jeff Garzik2a47ce02005-11-12 23:05:14 -0500389 void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
390 unsigned int port);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500391 void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
392 void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
393 void __iomem *mmio);
Jeff Garzikc9d39132005-11-13 17:47:51 -0500394 int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
395 unsigned int n_hc);
Jeff Garzik522479f2005-11-12 22:14:02 -0500396 void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
397 void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500398};
399
Brett Russ20f733e72005-09-01 18:26:17 -0400400struct mv_host_priv {
Brett Russ31961942005-09-30 01:36:00 -0400401 u32 hp_flags;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -0500402 struct mv_port_signal signal[8];
Jeff Garzik47c2b672005-11-12 21:13:17 -0500403 const struct mv_hw_ops *ops;
Brett Russ20f733e72005-09-01 18:26:17 -0400404};
405
406static void mv_irq_clear(struct ata_port *ap);
407static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
408static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
Jeff Garzikc9d39132005-11-13 17:47:51 -0500409static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
410static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
Brett Russ31961942005-09-30 01:36:00 -0400411static int mv_port_start(struct ata_port *ap);
412static void mv_port_stop(struct ata_port *ap);
413static void mv_qc_prep(struct ata_queued_cmd *qc);
Jeff Garzike4e7b892006-01-31 12:18:41 -0500414static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
Tejun Heo9a3d9eb2006-01-23 13:09:36 +0900415static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400416static void mv_error_handler(struct ata_port *ap);
417static void mv_post_int_cmd(struct ata_queued_cmd *qc);
418static void mv_eh_freeze(struct ata_port *ap);
419static void mv_eh_thaw(struct ata_port *ap);
Brett Russ20f733e72005-09-01 18:26:17 -0400420static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
421
Jeff Garzik2a47ce02005-11-12 23:05:14 -0500422static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
423 unsigned int port);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500424static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
425static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
426 void __iomem *mmio);
Jeff Garzikc9d39132005-11-13 17:47:51 -0500427static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
428 unsigned int n_hc);
Jeff Garzik522479f2005-11-12 22:14:02 -0500429static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
430static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500431
Jeff Garzik2a47ce02005-11-12 23:05:14 -0500432static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
433 unsigned int port);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500434static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
435static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
436 void __iomem *mmio);
Jeff Garzikc9d39132005-11-13 17:47:51 -0500437static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
438 unsigned int n_hc);
Jeff Garzik522479f2005-11-12 22:14:02 -0500439static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
440static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
Jeff Garzikc9d39132005-11-13 17:47:51 -0500441static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
442 unsigned int port_no);
Jeff Garzik47c2b672005-11-12 21:13:17 -0500443
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400444static struct scsi_host_template mv5_sht = {
Brett Russ20f733e72005-09-01 18:26:17 -0400445 .module = THIS_MODULE,
446 .name = DRV_NAME,
447 .ioctl = ata_scsi_ioctl,
448 .queuecommand = ata_scsi_queuecmd,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400449 .can_queue = ATA_DEF_QUEUE,
450 .this_id = ATA_SHT_THIS_ID,
451 .sg_tablesize = MV_MAX_SG_CT,
452 .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
453 .emulated = ATA_SHT_EMULATED,
454 .use_clustering = 1,
455 .proc_name = DRV_NAME,
456 .dma_boundary = MV_DMA_BOUNDARY,
457 .slave_configure = ata_scsi_slave_config,
458 .slave_destroy = ata_scsi_slave_destroy,
459 .bios_param = ata_std_bios_param,
460};
461
462static struct scsi_host_template mv6_sht = {
463 .module = THIS_MODULE,
464 .name = DRV_NAME,
465 .ioctl = ata_scsi_ioctl,
466 .queuecommand = ata_scsi_queuecmd,
467 .can_queue = ATA_DEF_QUEUE,
Brett Russ20f733e72005-09-01 18:26:17 -0400468 .this_id = ATA_SHT_THIS_ID,
Jeff Garzikd88184f2007-02-26 01:26:06 -0500469 .sg_tablesize = MV_MAX_SG_CT,
Brett Russ20f733e72005-09-01 18:26:17 -0400470 .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
471 .emulated = ATA_SHT_EMULATED,
Jeff Garzikd88184f2007-02-26 01:26:06 -0500472 .use_clustering = 1,
Brett Russ20f733e72005-09-01 18:26:17 -0400473 .proc_name = DRV_NAME,
474 .dma_boundary = MV_DMA_BOUNDARY,
475 .slave_configure = ata_scsi_slave_config,
Tejun Heoccf68c32006-05-31 18:28:09 +0900476 .slave_destroy = ata_scsi_slave_destroy,
Brett Russ20f733e72005-09-01 18:26:17 -0400477 .bios_param = ata_std_bios_param,
Brett Russ20f733e72005-09-01 18:26:17 -0400478};
479
Jeff Garzikc9d39132005-11-13 17:47:51 -0500480static const struct ata_port_operations mv5_ops = {
481 .port_disable = ata_port_disable,
482
483 .tf_load = ata_tf_load,
484 .tf_read = ata_tf_read,
485 .check_status = ata_check_status,
486 .exec_command = ata_exec_command,
487 .dev_select = ata_std_dev_select,
488
Jeff Garzikcffacd82007-03-09 09:46:47 -0500489 .cable_detect = ata_cable_sata,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500490
491 .qc_prep = mv_qc_prep,
492 .qc_issue = mv_qc_issue,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900493 .data_xfer = ata_data_xfer,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500494
Jeff Garzikc9d39132005-11-13 17:47:51 -0500495 .irq_clear = mv_irq_clear,
Akira Iguchi246ce3b2007-01-26 16:27:58 +0900496 .irq_on = ata_irq_on,
497 .irq_ack = ata_irq_ack,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500498
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400499 .error_handler = mv_error_handler,
500 .post_internal_cmd = mv_post_int_cmd,
501 .freeze = mv_eh_freeze,
502 .thaw = mv_eh_thaw,
503
Jeff Garzikc9d39132005-11-13 17:47:51 -0500504 .scr_read = mv5_scr_read,
505 .scr_write = mv5_scr_write,
506
507 .port_start = mv_port_start,
508 .port_stop = mv_port_stop,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500509};
510
511static const struct ata_port_operations mv6_ops = {
Brett Russ20f733e72005-09-01 18:26:17 -0400512 .port_disable = ata_port_disable,
513
514 .tf_load = ata_tf_load,
515 .tf_read = ata_tf_read,
516 .check_status = ata_check_status,
517 .exec_command = ata_exec_command,
518 .dev_select = ata_std_dev_select,
519
Jeff Garzikcffacd82007-03-09 09:46:47 -0500520 .cable_detect = ata_cable_sata,
Brett Russ20f733e72005-09-01 18:26:17 -0400521
Brett Russ31961942005-09-30 01:36:00 -0400522 .qc_prep = mv_qc_prep,
523 .qc_issue = mv_qc_issue,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900524 .data_xfer = ata_data_xfer,
Brett Russ20f733e72005-09-01 18:26:17 -0400525
Brett Russ20f733e72005-09-01 18:26:17 -0400526 .irq_clear = mv_irq_clear,
Akira Iguchi246ce3b2007-01-26 16:27:58 +0900527 .irq_on = ata_irq_on,
528 .irq_ack = ata_irq_ack,
Brett Russ20f733e72005-09-01 18:26:17 -0400529
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400530 .error_handler = mv_error_handler,
531 .post_internal_cmd = mv_post_int_cmd,
532 .freeze = mv_eh_freeze,
533 .thaw = mv_eh_thaw,
534
Brett Russ20f733e72005-09-01 18:26:17 -0400535 .scr_read = mv_scr_read,
536 .scr_write = mv_scr_write,
537
Brett Russ31961942005-09-30 01:36:00 -0400538 .port_start = mv_port_start,
539 .port_stop = mv_port_stop,
Brett Russ20f733e72005-09-01 18:26:17 -0400540};
541
Jeff Garzike4e7b892006-01-31 12:18:41 -0500542static const struct ata_port_operations mv_iie_ops = {
543 .port_disable = ata_port_disable,
544
545 .tf_load = ata_tf_load,
546 .tf_read = ata_tf_read,
547 .check_status = ata_check_status,
548 .exec_command = ata_exec_command,
549 .dev_select = ata_std_dev_select,
550
Jeff Garzikcffacd82007-03-09 09:46:47 -0500551 .cable_detect = ata_cable_sata,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500552
553 .qc_prep = mv_qc_prep_iie,
554 .qc_issue = mv_qc_issue,
Tejun Heo0d5ff562007-02-01 15:06:36 +0900555 .data_xfer = ata_data_xfer,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500556
Jeff Garzike4e7b892006-01-31 12:18:41 -0500557 .irq_clear = mv_irq_clear,
Akira Iguchi246ce3b2007-01-26 16:27:58 +0900558 .irq_on = ata_irq_on,
559 .irq_ack = ata_irq_ack,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500560
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400561 .error_handler = mv_error_handler,
562 .post_internal_cmd = mv_post_int_cmd,
563 .freeze = mv_eh_freeze,
564 .thaw = mv_eh_thaw,
565
Jeff Garzike4e7b892006-01-31 12:18:41 -0500566 .scr_read = mv_scr_read,
567 .scr_write = mv_scr_write,
568
569 .port_start = mv_port_start,
570 .port_stop = mv_port_stop,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500571};
572
Arjan van de Ven98ac62d2005-11-28 10:06:23 +0100573static const struct ata_port_info mv_port_info[] = {
Brett Russ20f733e72005-09-01 18:26:17 -0400574 { /* chip_504x */
Jeff Garzikcca39742006-08-24 03:19:22 -0400575 .flags = MV_COMMON_FLAGS,
Brett Russ31961942005-09-30 01:36:00 -0400576 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400577 .udma_mask = ATA_UDMA6,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500578 .port_ops = &mv5_ops,
Brett Russ20f733e72005-09-01 18:26:17 -0400579 },
580 { /* chip_508x */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400581 .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
Brett Russ31961942005-09-30 01:36:00 -0400582 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400583 .udma_mask = ATA_UDMA6,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500584 .port_ops = &mv5_ops,
Brett Russ20f733e72005-09-01 18:26:17 -0400585 },
Jeff Garzik47c2b672005-11-12 21:13:17 -0500586 { /* chip_5080 */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400587 .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500588 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400589 .udma_mask = ATA_UDMA6,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500590 .port_ops = &mv5_ops,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500591 },
Brett Russ20f733e72005-09-01 18:26:17 -0400592 { /* chip_604x */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400593 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
Brett Russ31961942005-09-30 01:36:00 -0400594 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400595 .udma_mask = ATA_UDMA6,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500596 .port_ops = &mv6_ops,
Brett Russ20f733e72005-09-01 18:26:17 -0400597 },
598 { /* chip_608x */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400599 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
600 MV_FLAG_DUAL_HC,
Brett Russ31961942005-09-30 01:36:00 -0400601 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400602 .udma_mask = ATA_UDMA6,
Jeff Garzikc9d39132005-11-13 17:47:51 -0500603 .port_ops = &mv6_ops,
Brett Russ20f733e72005-09-01 18:26:17 -0400604 },
Jeff Garzike4e7b892006-01-31 12:18:41 -0500605 { /* chip_6042 */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400606 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500607 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400608 .udma_mask = ATA_UDMA6,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500609 .port_ops = &mv_iie_ops,
610 },
611 { /* chip_7042 */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400612 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500613 .pio_mask = 0x1f, /* pio0-4 */
Jeff Garzikbf6263a2007-07-09 12:16:50 -0400614 .udma_mask = ATA_UDMA6,
Jeff Garzike4e7b892006-01-31 12:18:41 -0500615 .port_ops = &mv_iie_ops,
616 },
Brett Russ20f733e72005-09-01 18:26:17 -0400617};
618
Jeff Garzik3b7d6972005-11-10 11:04:11 -0500619static const struct pci_device_id mv_pci_tbl[] = {
Jeff Garzik2d2744f2006-09-28 20:21:59 -0400620 { PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
621 { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
622 { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
623 { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
Brett Russ20f733e72005-09-01 18:26:17 -0400624
Jeff Garzik2d2744f2006-09-28 20:21:59 -0400625 { PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
626 { PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
627 { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
628 { PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
629 { PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
Jeff Garzik29179532005-11-11 08:08:03 -0500630
Jeff Garzik2d2744f2006-09-28 20:21:59 -0400631 { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
632
Florian Attenbergerd9f9c6b2007-07-02 17:09:29 +0200633 /* Adaptec 1430SA */
634 { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
635
Olof Johanssone93f09d2007-01-18 18:39:59 -0600636 { PCI_VDEVICE(TTI, 0x2310), chip_7042 },
637
Morrison, Tom6a3d5862007-03-06 02:38:10 -0800638 /* add Marvell 7042 support */
639 { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
640
Jeff Garzik2d2744f2006-09-28 20:21:59 -0400641 { } /* terminate list */
Brett Russ20f733e72005-09-01 18:26:17 -0400642};
643
644static struct pci_driver mv_pci_driver = {
645 .name = DRV_NAME,
646 .id_table = mv_pci_tbl,
647 .probe = mv_init_one,
648 .remove = ata_pci_remove_one,
649};
650
Jeff Garzik47c2b672005-11-12 21:13:17 -0500651static const struct mv_hw_ops mv5xxx_ops = {
652 .phy_errata = mv5_phy_errata,
653 .enable_leds = mv5_enable_leds,
654 .read_preamp = mv5_read_preamp,
655 .reset_hc = mv5_reset_hc,
Jeff Garzik522479f2005-11-12 22:14:02 -0500656 .reset_flash = mv5_reset_flash,
657 .reset_bus = mv5_reset_bus,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500658};
659
660static const struct mv_hw_ops mv6xxx_ops = {
661 .phy_errata = mv6_phy_errata,
662 .enable_leds = mv6_enable_leds,
663 .read_preamp = mv6_read_preamp,
664 .reset_hc = mv6_reset_hc,
Jeff Garzik522479f2005-11-12 22:14:02 -0500665 .reset_flash = mv6_reset_flash,
666 .reset_bus = mv_reset_pci_bus,
Jeff Garzik47c2b672005-11-12 21:13:17 -0500667};
668
Brett Russ20f733e72005-09-01 18:26:17 -0400669/*
Jeff Garzikddef9bb2006-02-02 16:17:06 -0500670 * module options
671 */
672static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
673
674
Jeff Garzikd88184f2007-02-26 01:26:06 -0500675/* move to PCI layer or libata core? */
676static int pci_go_64(struct pci_dev *pdev)
677{
678 int rc;
679
680 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
681 rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
682 if (rc) {
683 rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
684 if (rc) {
685 dev_printk(KERN_ERR, &pdev->dev,
686 "64-bit DMA enable failed\n");
687 return rc;
688 }
689 }
690 } else {
691 rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
692 if (rc) {
693 dev_printk(KERN_ERR, &pdev->dev,
694 "32-bit DMA enable failed\n");
695 return rc;
696 }
697 rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
698 if (rc) {
699 dev_printk(KERN_ERR, &pdev->dev,
700 "32-bit consistent DMA enable failed\n");
701 return rc;
702 }
703 }
704
705 return rc;
706}
707
Jeff Garzikddef9bb2006-02-02 16:17:06 -0500708/*
Brett Russ20f733e72005-09-01 18:26:17 -0400709 * Functions
710 */
711
712static inline void writelfl(unsigned long data, void __iomem *addr)
713{
714 writel(data, addr);
715 (void) readl(addr); /* flush to avoid PCI posted write */
716}
717
Brett Russ20f733e72005-09-01 18:26:17 -0400718static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
719{
720 return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
721}
722
Jeff Garzikc9d39132005-11-13 17:47:51 -0500723static inline unsigned int mv_hc_from_port(unsigned int port)
724{
725 return port >> MV_PORT_HC_SHIFT;
726}
727
728static inline unsigned int mv_hardport_from_port(unsigned int port)
729{
730 return port & MV_PORT_MASK;
731}
732
733static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
734 unsigned int port)
735{
736 return mv_hc_base(base, mv_hc_from_port(port));
737}
738
Brett Russ20f733e72005-09-01 18:26:17 -0400739static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
740{
Jeff Garzikc9d39132005-11-13 17:47:51 -0500741 return mv_hc_base_from_port(base, port) +
Jeff Garzik8b260242005-11-12 12:32:50 -0500742 MV_SATAHC_ARBTR_REG_SZ +
Jeff Garzikc9d39132005-11-13 17:47:51 -0500743 (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
Brett Russ20f733e72005-09-01 18:26:17 -0400744}
745
746static inline void __iomem *mv_ap_base(struct ata_port *ap)
747{
Tejun Heo0d5ff562007-02-01 15:06:36 +0900748 return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
Brett Russ20f733e72005-09-01 18:26:17 -0400749}
750
Jeff Garzikcca39742006-08-24 03:19:22 -0400751static inline int mv_get_hc_count(unsigned long port_flags)
Brett Russ20f733e72005-09-01 18:26:17 -0400752{
Jeff Garzikcca39742006-08-24 03:19:22 -0400753 return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
Brett Russ20f733e72005-09-01 18:26:17 -0400754}
755
756static void mv_irq_clear(struct ata_port *ap)
757{
758}
759
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400760static void mv_set_edma_ptrs(void __iomem *port_mmio,
761 struct mv_host_priv *hpriv,
762 struct mv_port_priv *pp)
763{
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400764 u32 index;
765
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400766 /*
767 * initialize request queue
768 */
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400769 index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
770
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400771 WARN_ON(pp->crqb_dma & 0x3ff);
772 writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400773 writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400774 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
775
776 if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400777 writelfl((pp->crqb_dma & 0xffffffff) | index,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400778 port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
779 else
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400780 writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400781
782 /*
783 * initialize response queue
784 */
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400785 index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
786
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400787 WARN_ON(pp->crpb_dma & 0xff);
788 writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
789
790 if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400791 writelfl((pp->crpb_dma & 0xffffffff) | index,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400792 port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
793 else
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400794 writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400795
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400796 writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400797 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400798}
799
Brett Russ05b308e2005-10-05 17:08:53 -0400800/**
801 * mv_start_dma - Enable eDMA engine
802 * @base: port base address
803 * @pp: port private data
804 *
Tejun Heobeec7db2006-02-11 19:11:13 +0900805 * Verify the local cache of the eDMA state is accurate with a
806 * WARN_ON.
Brett Russ05b308e2005-10-05 17:08:53 -0400807 *
808 * LOCKING:
809 * Inherited from caller.
810 */
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400811static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
812 struct mv_port_priv *pp)
Brett Russ31961942005-09-30 01:36:00 -0400813{
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400814 if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -0400815 /* clear EDMA event indicators, if any */
816 writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
817
818 mv_set_edma_ptrs(base, hpriv, pp);
819
Brett Russafb0edd2005-10-05 17:08:42 -0400820 writelfl(EDMA_EN, base + EDMA_CMD_OFS);
821 pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
822 }
Tejun Heobeec7db2006-02-11 19:11:13 +0900823 WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
Brett Russ31961942005-09-30 01:36:00 -0400824}
825
Brett Russ05b308e2005-10-05 17:08:53 -0400826/**
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400827 * __mv_stop_dma - Disable eDMA engine
Brett Russ05b308e2005-10-05 17:08:53 -0400828 * @ap: ATA channel to manipulate
829 *
Tejun Heobeec7db2006-02-11 19:11:13 +0900830 * Verify the local cache of the eDMA state is accurate with a
831 * WARN_ON.
Brett Russ05b308e2005-10-05 17:08:53 -0400832 *
833 * LOCKING:
834 * Inherited from caller.
835 */
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400836static int __mv_stop_dma(struct ata_port *ap)
Brett Russ31961942005-09-30 01:36:00 -0400837{
838 void __iomem *port_mmio = mv_ap_base(ap);
839 struct mv_port_priv *pp = ap->private_data;
Brett Russ31961942005-09-30 01:36:00 -0400840 u32 reg;
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400841 int i, err = 0;
Brett Russ31961942005-09-30 01:36:00 -0400842
Jeff Garzik4537deb52007-07-12 14:30:19 -0400843 if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
Brett Russafb0edd2005-10-05 17:08:42 -0400844 /* Disable EDMA if active. The disable bit auto clears.
Brett Russ31961942005-09-30 01:36:00 -0400845 */
Brett Russ31961942005-09-30 01:36:00 -0400846 writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
847 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
Brett Russafb0edd2005-10-05 17:08:42 -0400848 } else {
Tejun Heobeec7db2006-02-11 19:11:13 +0900849 WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
Brett Russafb0edd2005-10-05 17:08:42 -0400850 }
Jeff Garzik8b260242005-11-12 12:32:50 -0500851
Brett Russ31961942005-09-30 01:36:00 -0400852 /* now properly wait for the eDMA to stop */
853 for (i = 1000; i > 0; i--) {
854 reg = readl(port_mmio + EDMA_CMD_OFS);
Jeff Garzik4537deb52007-07-12 14:30:19 -0400855 if (!(reg & EDMA_EN))
Brett Russ31961942005-09-30 01:36:00 -0400856 break;
Jeff Garzik4537deb52007-07-12 14:30:19 -0400857
Brett Russ31961942005-09-30 01:36:00 -0400858 udelay(100);
859 }
860
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400861 if (reg & EDMA_EN) {
Tejun Heof15a1da2006-05-15 20:57:56 +0900862 ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400863 err = -EIO;
Brett Russ31961942005-09-30 01:36:00 -0400864 }
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400865
866 return err;
Brett Russ31961942005-09-30 01:36:00 -0400867}
868
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400869static int mv_stop_dma(struct ata_port *ap)
870{
871 unsigned long flags;
872 int rc;
873
874 spin_lock_irqsave(&ap->host->lock, flags);
875 rc = __mv_stop_dma(ap);
876 spin_unlock_irqrestore(&ap->host->lock, flags);
877
878 return rc;
879}
880
Jeff Garzik8a70f8d2005-10-05 17:19:47 -0400881#ifdef ATA_DEBUG
Brett Russ31961942005-09-30 01:36:00 -0400882static void mv_dump_mem(void __iomem *start, unsigned bytes)
883{
Brett Russ31961942005-09-30 01:36:00 -0400884 int b, w;
885 for (b = 0; b < bytes; ) {
886 DPRINTK("%p: ", start + b);
887 for (w = 0; b < bytes && w < 4; w++) {
888 printk("%08x ",readl(start + b));
889 b += sizeof(u32);
890 }
891 printk("\n");
892 }
Brett Russ31961942005-09-30 01:36:00 -0400893}
Jeff Garzik8a70f8d2005-10-05 17:19:47 -0400894#endif
895
Brett Russ31961942005-09-30 01:36:00 -0400896static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
897{
898#ifdef ATA_DEBUG
899 int b, w;
900 u32 dw;
901 for (b = 0; b < bytes; ) {
902 DPRINTK("%02x: ", b);
903 for (w = 0; b < bytes && w < 4; w++) {
904 (void) pci_read_config_dword(pdev,b,&dw);
905 printk("%08x ",dw);
906 b += sizeof(u32);
907 }
908 printk("\n");
909 }
910#endif
911}
912static void mv_dump_all_regs(void __iomem *mmio_base, int port,
913 struct pci_dev *pdev)
914{
915#ifdef ATA_DEBUG
Jeff Garzik8b260242005-11-12 12:32:50 -0500916 void __iomem *hc_base = mv_hc_base(mmio_base,
Brett Russ31961942005-09-30 01:36:00 -0400917 port >> MV_PORT_HC_SHIFT);
918 void __iomem *port_base;
919 int start_port, num_ports, p, start_hc, num_hcs, hc;
920
921 if (0 > port) {
922 start_hc = start_port = 0;
923 num_ports = 8; /* shld be benign for 4 port devs */
924 num_hcs = 2;
925 } else {
926 start_hc = port >> MV_PORT_HC_SHIFT;
927 start_port = port;
928 num_ports = num_hcs = 1;
929 }
Jeff Garzik8b260242005-11-12 12:32:50 -0500930 DPRINTK("All registers for port(s) %u-%u:\n", start_port,
Brett Russ31961942005-09-30 01:36:00 -0400931 num_ports > 1 ? num_ports - 1 : start_port);
932
933 if (NULL != pdev) {
934 DPRINTK("PCI config space regs:\n");
935 mv_dump_pci_cfg(pdev, 0x68);
936 }
937 DPRINTK("PCI regs:\n");
938 mv_dump_mem(mmio_base+0xc00, 0x3c);
939 mv_dump_mem(mmio_base+0xd00, 0x34);
940 mv_dump_mem(mmio_base+0xf00, 0x4);
941 mv_dump_mem(mmio_base+0x1d00, 0x6c);
942 for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
Dan Alonid220c37e2006-04-10 23:20:22 -0700943 hc_base = mv_hc_base(mmio_base, hc);
Brett Russ31961942005-09-30 01:36:00 -0400944 DPRINTK("HC regs (HC %i):\n", hc);
945 mv_dump_mem(hc_base, 0x1c);
946 }
947 for (p = start_port; p < start_port + num_ports; p++) {
948 port_base = mv_port_base(mmio_base, p);
949 DPRINTK("EDMA regs (port %i):\n",p);
950 mv_dump_mem(port_base, 0x54);
951 DPRINTK("SATA regs (port %i):\n",p);
952 mv_dump_mem(port_base+0x300, 0x60);
953 }
954#endif
955}
956
Brett Russ20f733e72005-09-01 18:26:17 -0400957static unsigned int mv_scr_offset(unsigned int sc_reg_in)
958{
959 unsigned int ofs;
960
961 switch (sc_reg_in) {
962 case SCR_STATUS:
963 case SCR_CONTROL:
964 case SCR_ERROR:
965 ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
966 break;
967 case SCR_ACTIVE:
968 ofs = SATA_ACTIVE_OFS; /* active is not with the others */
969 break;
970 default:
971 ofs = 0xffffffffU;
972 break;
973 }
974 return ofs;
975}
976
977static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
978{
979 unsigned int ofs = mv_scr_offset(sc_reg_in);
980
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400981 if (ofs != 0xffffffffU)
Brett Russ20f733e72005-09-01 18:26:17 -0400982 return readl(mv_ap_base(ap) + ofs);
Jeff Garzik35177262007-02-24 21:26:42 -0500983 else
Brett Russ20f733e72005-09-01 18:26:17 -0400984 return (u32) ofs;
Brett Russ20f733e72005-09-01 18:26:17 -0400985}
986
987static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
988{
989 unsigned int ofs = mv_scr_offset(sc_reg_in);
990
Jeff Garzik0ea9e172007-07-13 17:06:45 -0400991 if (ofs != 0xffffffffU)
Brett Russ20f733e72005-09-01 18:26:17 -0400992 writelfl(val, mv_ap_base(ap) + ofs);
Brett Russ20f733e72005-09-01 18:26:17 -0400993}
994
Jeff Garzikc5d3e452007-07-11 18:30:50 -0400995static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
996 void __iomem *port_mmio)
Jeff Garzike4e7b892006-01-31 12:18:41 -0500997{
998 u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
999
1000 /* set up non-NCQ EDMA configuration */
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001001 cfg &= ~(1 << 9); /* disable eQue */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001002
Jeff Garzike728eab2007-02-25 02:53:41 -05001003 if (IS_GEN_I(hpriv)) {
1004 cfg &= ~0x1f; /* clear queue depth */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001005 cfg |= (1 << 8); /* enab config burst size mask */
Jeff Garzike728eab2007-02-25 02:53:41 -05001006 }
Jeff Garzike4e7b892006-01-31 12:18:41 -05001007
Jeff Garzike728eab2007-02-25 02:53:41 -05001008 else if (IS_GEN_II(hpriv)) {
1009 cfg &= ~0x1f; /* clear queue depth */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001010 cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
Jeff Garzike728eab2007-02-25 02:53:41 -05001011 cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
1012 }
Jeff Garzike4e7b892006-01-31 12:18:41 -05001013
1014 else if (IS_GEN_IIE(hpriv)) {
Jeff Garzike728eab2007-02-25 02:53:41 -05001015 cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
1016 cfg |= (1 << 22); /* enab 4-entry host queue cache */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001017 cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
1018 cfg |= (1 << 18); /* enab early completion */
Jeff Garzike728eab2007-02-25 02:53:41 -05001019 cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
1020 cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
Jeff Garzik4537deb52007-07-12 14:30:19 -04001021 cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001022 }
1023
1024 writelfl(cfg, port_mmio + EDMA_CFG_OFS);
1025}
1026
Brett Russ05b308e2005-10-05 17:08:53 -04001027/**
1028 * mv_port_start - Port specific init/start routine.
1029 * @ap: ATA channel to manipulate
1030 *
1031 * Allocate and point to DMA memory, init port private memory,
1032 * zero indices.
1033 *
1034 * LOCKING:
1035 * Inherited from caller.
1036 */
Brett Russ31961942005-09-30 01:36:00 -04001037static int mv_port_start(struct ata_port *ap)
1038{
Jeff Garzikcca39742006-08-24 03:19:22 -04001039 struct device *dev = ap->host->dev;
1040 struct mv_host_priv *hpriv = ap->host->private_data;
Brett Russ31961942005-09-30 01:36:00 -04001041 struct mv_port_priv *pp;
1042 void __iomem *port_mmio = mv_ap_base(ap);
1043 void *mem;
1044 dma_addr_t mem_dma;
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001045 unsigned long flags;
Tejun Heo24dc5f32007-01-20 16:00:28 +09001046 int rc;
Brett Russ31961942005-09-30 01:36:00 -04001047
Tejun Heo24dc5f32007-01-20 16:00:28 +09001048 pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
Jeff Garzik6037d6b2005-11-04 22:08:00 -05001049 if (!pp)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001050 return -ENOMEM;
Brett Russ31961942005-09-30 01:36:00 -04001051
Tejun Heo24dc5f32007-01-20 16:00:28 +09001052 mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
1053 GFP_KERNEL);
Jeff Garzik6037d6b2005-11-04 22:08:00 -05001054 if (!mem)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001055 return -ENOMEM;
Brett Russ31961942005-09-30 01:36:00 -04001056 memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
1057
Jeff Garzik6037d6b2005-11-04 22:08:00 -05001058 rc = ata_pad_alloc(ap, dev);
1059 if (rc)
Tejun Heo24dc5f32007-01-20 16:00:28 +09001060 return rc;
Jeff Garzik6037d6b2005-11-04 22:08:00 -05001061
Jeff Garzik8b260242005-11-12 12:32:50 -05001062 /* First item in chunk of DMA memory:
Brett Russ31961942005-09-30 01:36:00 -04001063 * 32-slot command request table (CRQB), 32 bytes each in size
1064 */
1065 pp->crqb = mem;
1066 pp->crqb_dma = mem_dma;
1067 mem += MV_CRQB_Q_SZ;
1068 mem_dma += MV_CRQB_Q_SZ;
1069
Jeff Garzik8b260242005-11-12 12:32:50 -05001070 /* Second item:
Brett Russ31961942005-09-30 01:36:00 -04001071 * 32-slot command response table (CRPB), 8 bytes each in size
1072 */
1073 pp->crpb = mem;
1074 pp->crpb_dma = mem_dma;
1075 mem += MV_CRPB_Q_SZ;
1076 mem_dma += MV_CRPB_Q_SZ;
1077
1078 /* Third item:
1079 * Table of scatter-gather descriptors (ePRD), 16 bytes each
1080 */
1081 pp->sg_tbl = mem;
1082 pp->sg_tbl_dma = mem_dma;
1083
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001084 spin_lock_irqsave(&ap->host->lock, flags);
1085
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001086 mv_edma_cfg(ap, hpriv, port_mmio);
Brett Russ31961942005-09-30 01:36:00 -04001087
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001088 mv_set_edma_ptrs(port_mmio, hpriv, pp);
Brett Russ31961942005-09-30 01:36:00 -04001089
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001090 spin_unlock_irqrestore(&ap->host->lock, flags);
1091
Brett Russ31961942005-09-30 01:36:00 -04001092 /* Don't turn on EDMA here...do it before DMA commands only. Else
1093 * we'll be unable to send non-data, PIO, etc due to restricted access
1094 * to shadow regs.
1095 */
1096 ap->private_data = pp;
1097 return 0;
1098}
1099
Brett Russ05b308e2005-10-05 17:08:53 -04001100/**
1101 * mv_port_stop - Port specific cleanup/stop routine.
1102 * @ap: ATA channel to manipulate
1103 *
1104 * Stop DMA, cleanup port memory.
1105 *
1106 * LOCKING:
Jeff Garzikcca39742006-08-24 03:19:22 -04001107 * This routine uses the host lock to protect the DMA stop.
Brett Russ05b308e2005-10-05 17:08:53 -04001108 */
Brett Russ31961942005-09-30 01:36:00 -04001109static void mv_port_stop(struct ata_port *ap)
1110{
Brett Russ31961942005-09-30 01:36:00 -04001111 mv_stop_dma(ap);
Brett Russ31961942005-09-30 01:36:00 -04001112}
1113
Brett Russ05b308e2005-10-05 17:08:53 -04001114/**
1115 * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
1116 * @qc: queued command whose SG list to source from
1117 *
1118 * Populate the SG list and mark the last entry.
1119 *
1120 * LOCKING:
1121 * Inherited from caller.
1122 */
Jeff Garzikd88184f2007-02-26 01:26:06 -05001123static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
Brett Russ31961942005-09-30 01:36:00 -04001124{
1125 struct mv_port_priv *pp = qc->ap->private_data;
Jeff Garzikd88184f2007-02-26 01:26:06 -05001126 unsigned int n_sg = 0;
Jeff Garzik972c26b2005-10-18 22:14:54 -04001127 struct scatterlist *sg;
Jeff Garzikd88184f2007-02-26 01:26:06 -05001128 struct mv_sg *mv_sg;
Brett Russ31961942005-09-30 01:36:00 -04001129
Jeff Garzikd88184f2007-02-26 01:26:06 -05001130 mv_sg = pp->sg_tbl;
Jeff Garzik972c26b2005-10-18 22:14:54 -04001131 ata_for_each_sg(sg, qc) {
Jeff Garzikd88184f2007-02-26 01:26:06 -05001132 dma_addr_t addr = sg_dma_address(sg);
1133 u32 sg_len = sg_dma_len(sg);
Brett Russ31961942005-09-30 01:36:00 -04001134
Jeff Garzikd88184f2007-02-26 01:26:06 -05001135 mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
1136 mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1137 mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
Brett Russ31961942005-09-30 01:36:00 -04001138
Jeff Garzikd88184f2007-02-26 01:26:06 -05001139 if (ata_sg_is_last(sg, qc))
1140 mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
Jeff Garzik972c26b2005-10-18 22:14:54 -04001141
Jeff Garzikd88184f2007-02-26 01:26:06 -05001142 mv_sg++;
1143 n_sg++;
Brett Russ31961942005-09-30 01:36:00 -04001144 }
Jeff Garzikd88184f2007-02-26 01:26:06 -05001145
1146 return n_sg;
Brett Russ31961942005-09-30 01:36:00 -04001147}
1148
Mark Lorde1469872006-05-22 19:02:03 -04001149static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
Brett Russ31961942005-09-30 01:36:00 -04001150{
Mark Lord559eeda2006-05-19 16:40:15 -04001151 u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
Brett Russ31961942005-09-30 01:36:00 -04001152 (last ? CRQB_CMD_LAST : 0);
Mark Lord559eeda2006-05-19 16:40:15 -04001153 *cmdw = cpu_to_le16(tmp);
Brett Russ31961942005-09-30 01:36:00 -04001154}
1155
Brett Russ05b308e2005-10-05 17:08:53 -04001156/**
1157 * mv_qc_prep - Host specific command preparation.
1158 * @qc: queued command to prepare
1159 *
1160 * This routine simply redirects to the general purpose routine
1161 * if command is not DMA. Else, it handles prep of the CRQB
1162 * (command request block), does some sanity checking, and calls
1163 * the SG load routine.
1164 *
1165 * LOCKING:
1166 * Inherited from caller.
1167 */
Brett Russ31961942005-09-30 01:36:00 -04001168static void mv_qc_prep(struct ata_queued_cmd *qc)
1169{
1170 struct ata_port *ap = qc->ap;
1171 struct mv_port_priv *pp = ap->private_data;
Mark Lorde1469872006-05-22 19:02:03 -04001172 __le16 *cw;
Brett Russ31961942005-09-30 01:36:00 -04001173 struct ata_taskfile *tf;
1174 u16 flags = 0;
Mark Lorda6432432006-05-19 16:36:36 -04001175 unsigned in_index;
Brett Russ31961942005-09-30 01:36:00 -04001176
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001177 if (qc->tf.protocol != ATA_PROT_DMA)
Brett Russ31961942005-09-30 01:36:00 -04001178 return;
Brett Russ20f733e72005-09-01 18:26:17 -04001179
Brett Russ31961942005-09-30 01:36:00 -04001180 /* Fill in command request block
1181 */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001182 if (!(qc->tf.flags & ATA_TFLAG_WRITE))
Brett Russ31961942005-09-30 01:36:00 -04001183 flags |= CRQB_FLAG_READ;
Tejun Heobeec7db2006-02-11 19:11:13 +09001184 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
Brett Russ31961942005-09-30 01:36:00 -04001185 flags |= qc->tag << CRQB_TAG_SHIFT;
Jeff Garzik4537deb52007-07-12 14:30:19 -04001186 flags |= qc->tag << CRQB_IOID_SHIFT; /* 50xx appears to ignore this*/
Brett Russ31961942005-09-30 01:36:00 -04001187
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001188 /* get current queue index from software */
1189 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
Brett Russ31961942005-09-30 01:36:00 -04001190
Mark Lorda6432432006-05-19 16:36:36 -04001191 pp->crqb[in_index].sg_addr =
1192 cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1193 pp->crqb[in_index].sg_addr_hi =
1194 cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1195 pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
1196
1197 cw = &pp->crqb[in_index].ata_cmd[0];
Brett Russ31961942005-09-30 01:36:00 -04001198 tf = &qc->tf;
1199
1200 /* Sadly, the CRQB cannot accomodate all registers--there are
1201 * only 11 bytes...so we must pick and choose required
1202 * registers based on the command. So, we drop feature and
1203 * hob_feature for [RW] DMA commands, but they are needed for
1204 * NCQ. NCQ will drop hob_nsect.
1205 */
1206 switch (tf->command) {
1207 case ATA_CMD_READ:
1208 case ATA_CMD_READ_EXT:
1209 case ATA_CMD_WRITE:
1210 case ATA_CMD_WRITE_EXT:
Jens Axboec15d85c2006-02-15 15:59:25 +01001211 case ATA_CMD_WRITE_FUA_EXT:
Brett Russ31961942005-09-30 01:36:00 -04001212 mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
1213 break;
1214#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
1215 case ATA_CMD_FPDMA_READ:
1216 case ATA_CMD_FPDMA_WRITE:
Jeff Garzik8b260242005-11-12 12:32:50 -05001217 mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
Brett Russ31961942005-09-30 01:36:00 -04001218 mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
1219 break;
1220#endif /* FIXME: remove this line when NCQ added */
1221 default:
1222 /* The only other commands EDMA supports in non-queued and
1223 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
1224 * of which are defined/used by Linux. If we get here, this
1225 * driver needs work.
1226 *
1227 * FIXME: modify libata to give qc_prep a return value and
1228 * return error here.
1229 */
1230 BUG_ON(tf->command);
1231 break;
1232 }
1233 mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
1234 mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
1235 mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
1236 mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
1237 mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
1238 mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
1239 mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
1240 mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
1241 mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
1242
Jeff Garzike4e7b892006-01-31 12:18:41 -05001243 if (!(qc->flags & ATA_QCFLAG_DMAMAP))
Brett Russ31961942005-09-30 01:36:00 -04001244 return;
Jeff Garzike4e7b892006-01-31 12:18:41 -05001245 mv_fill_sg(qc);
1246}
1247
1248/**
1249 * mv_qc_prep_iie - Host specific command preparation.
1250 * @qc: queued command to prepare
1251 *
1252 * This routine simply redirects to the general purpose routine
1253 * if command is not DMA. Else, it handles prep of the CRQB
1254 * (command request block), does some sanity checking, and calls
1255 * the SG load routine.
1256 *
1257 * LOCKING:
1258 * Inherited from caller.
1259 */
1260static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1261{
1262 struct ata_port *ap = qc->ap;
1263 struct mv_port_priv *pp = ap->private_data;
1264 struct mv_crqb_iie *crqb;
1265 struct ata_taskfile *tf;
Mark Lorda6432432006-05-19 16:36:36 -04001266 unsigned in_index;
Jeff Garzike4e7b892006-01-31 12:18:41 -05001267 u32 flags = 0;
1268
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001269 if (qc->tf.protocol != ATA_PROT_DMA)
Jeff Garzike4e7b892006-01-31 12:18:41 -05001270 return;
1271
Jeff Garzike4e7b892006-01-31 12:18:41 -05001272 /* Fill in Gen IIE command request block
1273 */
1274 if (!(qc->tf.flags & ATA_TFLAG_WRITE))
1275 flags |= CRQB_FLAG_READ;
1276
Tejun Heobeec7db2006-02-11 19:11:13 +09001277 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
Jeff Garzike4e7b892006-01-31 12:18:41 -05001278 flags |= qc->tag << CRQB_TAG_SHIFT;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001279 flags |= qc->tag << CRQB_IOID_SHIFT; /* "I/O Id" is -really-
Jeff Garzik4537deb52007-07-12 14:30:19 -04001280 what we use as our tag */
Jeff Garzike4e7b892006-01-31 12:18:41 -05001281
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001282 /* get current queue index from software */
1283 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
Mark Lorda6432432006-05-19 16:36:36 -04001284
1285 crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
Jeff Garzike4e7b892006-01-31 12:18:41 -05001286 crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
1287 crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
1288 crqb->flags = cpu_to_le32(flags);
1289
1290 tf = &qc->tf;
1291 crqb->ata_cmd[0] = cpu_to_le32(
1292 (tf->command << 16) |
1293 (tf->feature << 24)
1294 );
1295 crqb->ata_cmd[1] = cpu_to_le32(
1296 (tf->lbal << 0) |
1297 (tf->lbam << 8) |
1298 (tf->lbah << 16) |
1299 (tf->device << 24)
1300 );
1301 crqb->ata_cmd[2] = cpu_to_le32(
1302 (tf->hob_lbal << 0) |
1303 (tf->hob_lbam << 8) |
1304 (tf->hob_lbah << 16) |
1305 (tf->hob_feature << 24)
1306 );
1307 crqb->ata_cmd[3] = cpu_to_le32(
1308 (tf->nsect << 0) |
1309 (tf->hob_nsect << 8)
1310 );
1311
1312 if (!(qc->flags & ATA_QCFLAG_DMAMAP))
1313 return;
Brett Russ31961942005-09-30 01:36:00 -04001314 mv_fill_sg(qc);
1315}
1316
Brett Russ05b308e2005-10-05 17:08:53 -04001317/**
1318 * mv_qc_issue - Initiate a command to the host
1319 * @qc: queued command to start
1320 *
1321 * This routine simply redirects to the general purpose routine
1322 * if command is not DMA. Else, it sanity checks our local
1323 * caches of the request producer/consumer indices then enables
1324 * DMA and bumps the request producer index.
1325 *
1326 * LOCKING:
1327 * Inherited from caller.
1328 */
Tejun Heo9a3d9eb2006-01-23 13:09:36 +09001329static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
Brett Russ31961942005-09-30 01:36:00 -04001330{
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001331 struct ata_port *ap = qc->ap;
1332 void __iomem *port_mmio = mv_ap_base(ap);
1333 struct mv_port_priv *pp = ap->private_data;
1334 struct mv_host_priv *hpriv = ap->host->private_data;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001335 u32 in_index;
Brett Russ31961942005-09-30 01:36:00 -04001336
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001337 if (qc->tf.protocol != ATA_PROT_DMA) {
Brett Russ31961942005-09-30 01:36:00 -04001338 /* We're about to send a non-EDMA capable command to the
1339 * port. Turn off EDMA so there won't be problems accessing
1340 * shadow block, etc registers.
1341 */
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001342 __mv_stop_dma(ap);
Brett Russ31961942005-09-30 01:36:00 -04001343 return ata_qc_issue_prot(qc);
1344 }
1345
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001346 mv_start_dma(port_mmio, hpriv, pp);
1347
1348 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
Brett Russ31961942005-09-30 01:36:00 -04001349
Brett Russ31961942005-09-30 01:36:00 -04001350 /* until we do queuing, the queue should be empty at this point */
Mark Lorda6432432006-05-19 16:36:36 -04001351 WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
1352 >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
Brett Russ31961942005-09-30 01:36:00 -04001353
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001354 pp->req_idx++;
Brett Russ31961942005-09-30 01:36:00 -04001355
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001356 in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
Brett Russ31961942005-09-30 01:36:00 -04001357
1358 /* and write the request in pointer to kick the EDMA to life */
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001359 writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
1360 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
Brett Russ31961942005-09-30 01:36:00 -04001361
1362 return 0;
1363}
1364
Brett Russ05b308e2005-10-05 17:08:53 -04001365/**
Brett Russ05b308e2005-10-05 17:08:53 -04001366 * mv_err_intr - Handle error interrupts on the port
1367 * @ap: ATA channel to manipulate
Mark Lord9b358e32006-05-19 16:21:03 -04001368 * @reset_allowed: bool: 0 == don't trigger from reset here
Brett Russ05b308e2005-10-05 17:08:53 -04001369 *
1370 * In most cases, just clear the interrupt and move on. However,
1371 * some cases require an eDMA reset, which is done right before
1372 * the COMRESET in mv_phy_reset(). The SERR case requires a
1373 * clear of pending errors in the SATA SERROR register. Finally,
1374 * if the port disabled DMA, update our cached copy to match.
1375 *
1376 * LOCKING:
1377 * Inherited from caller.
1378 */
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001379static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
Brett Russ20f733e72005-09-01 18:26:17 -04001380{
Brett Russ31961942005-09-30 01:36:00 -04001381 void __iomem *port_mmio = mv_ap_base(ap);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001382 u32 edma_err_cause, eh_freeze_mask, serr = 0;
1383 struct mv_port_priv *pp = ap->private_data;
1384 struct mv_host_priv *hpriv = ap->host->private_data;
1385 unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
1386 unsigned int action = 0, err_mask = 0;
1387 struct ata_eh_info *ehi = &ap->eh_info;
Brett Russ20f733e72005-09-01 18:26:17 -04001388
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001389 ata_ehi_clear_desc(ehi);
Brett Russ20f733e72005-09-01 18:26:17 -04001390
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001391 if (!edma_enabled) {
1392 /* just a guess: do we need to do this? should we
1393 * expand this, and do it in all cases?
1394 */
Tejun Heo81952c52006-05-15 20:57:47 +09001395 sata_scr_read(ap, SCR_ERROR, &serr);
1396 sata_scr_write_flush(ap, SCR_ERROR, serr);
Brett Russ20f733e72005-09-01 18:26:17 -04001397 }
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001398
1399 edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1400
1401 ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
1402
1403 /*
1404 * all generations share these EDMA error cause bits
1405 */
1406
1407 if (edma_err_cause & EDMA_ERR_DEV)
1408 err_mask |= AC_ERR_DEV;
1409 if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001410 EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001411 EDMA_ERR_INTRL_PAR)) {
1412 err_mask |= AC_ERR_ATA_BUS;
1413 action |= ATA_EH_HARDRESET;
Tejun Heob64bbc32007-07-16 14:29:39 +09001414 ata_ehi_push_desc(ehi, "parity error");
Brett Russafb0edd2005-10-05 17:08:42 -04001415 }
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001416 if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
1417 ata_ehi_hotplugged(ehi);
1418 ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
Tejun Heob64bbc32007-07-16 14:29:39 +09001419 "dev disconnect" : "dev connect");
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001420 }
1421
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04001422 if (IS_GEN_I(hpriv)) {
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001423 eh_freeze_mask = EDMA_EH_FREEZE_5;
1424
1425 if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
1426 struct mv_port_priv *pp = ap->private_data;
1427 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
Tejun Heob64bbc32007-07-16 14:29:39 +09001428 ata_ehi_push_desc(ehi, "EDMA self-disable");
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001429 }
1430 } else {
1431 eh_freeze_mask = EDMA_EH_FREEZE;
1432
1433 if (edma_err_cause & EDMA_ERR_SELF_DIS) {
1434 struct mv_port_priv *pp = ap->private_data;
1435 pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
Tejun Heob64bbc32007-07-16 14:29:39 +09001436 ata_ehi_push_desc(ehi, "EDMA self-disable");
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001437 }
1438
1439 if (edma_err_cause & EDMA_ERR_SERR) {
1440 sata_scr_read(ap, SCR_ERROR, &serr);
1441 sata_scr_write_flush(ap, SCR_ERROR, serr);
1442 err_mask = AC_ERR_ATA_BUS;
1443 action |= ATA_EH_HARDRESET;
1444 }
1445 }
Brett Russ20f733e72005-09-01 18:26:17 -04001446
1447 /* Clear EDMA now that SERR cleanup done */
1448 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1449
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001450 if (!err_mask) {
1451 err_mask = AC_ERR_OTHER;
1452 action |= ATA_EH_HARDRESET;
1453 }
1454
1455 ehi->serror |= serr;
1456 ehi->action |= action;
1457
1458 if (qc)
1459 qc->err_mask |= err_mask;
1460 else
1461 ehi->err_mask |= err_mask;
1462
1463 if (edma_err_cause & eh_freeze_mask)
1464 ata_port_freeze(ap);
1465 else
1466 ata_port_abort(ap);
1467}
1468
1469static void mv_intr_pio(struct ata_port *ap)
1470{
1471 struct ata_queued_cmd *qc;
1472 u8 ata_status;
1473
1474 /* ignore spurious intr if drive still BUSY */
1475 ata_status = readb(ap->ioaddr.status_addr);
1476 if (unlikely(ata_status & ATA_BUSY))
1477 return;
1478
1479 /* get active ATA command */
1480 qc = ata_qc_from_tag(ap, ap->active_tag);
1481 if (unlikely(!qc)) /* no active tag */
1482 return;
1483 if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
1484 return;
1485
1486 /* and finally, complete the ATA command */
1487 qc->err_mask |= ac_err_mask(ata_status);
1488 ata_qc_complete(qc);
1489}
1490
1491static void mv_intr_edma(struct ata_port *ap)
1492{
1493 void __iomem *port_mmio = mv_ap_base(ap);
1494 struct mv_host_priv *hpriv = ap->host->private_data;
1495 struct mv_port_priv *pp = ap->private_data;
1496 struct ata_queued_cmd *qc;
1497 u32 out_index, in_index;
1498 bool work_done = false;
1499
1500 /* get h/w response queue pointer */
1501 in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
1502 >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
1503
1504 while (1) {
1505 u16 status;
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001506 unsigned int tag;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001507
1508 /* get s/w response queue last-read pointer, and compare */
1509 out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
1510 if (in_index == out_index)
1511 break;
1512
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001513 /* 50xx: get active ATA command */
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001514 if (IS_GEN_I(hpriv))
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001515 tag = ap->active_tag;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001516
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001517 /* Gen II/IIE: get active ATA command via tag, to enable
1518 * support for queueing. this works transparently for
1519 * queued and non-queued modes.
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001520 */
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001521 else if (IS_GEN_II(hpriv))
1522 tag = (le16_to_cpu(pp->crpb[out_index].id)
1523 >> CRPB_IOID_SHIFT_6) & 0x3f;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001524
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001525 else /* IS_GEN_IIE */
1526 tag = (le16_to_cpu(pp->crpb[out_index].id)
1527 >> CRPB_IOID_SHIFT_7) & 0x3f;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001528
Jeff Garzik6c1153e2007-07-13 15:20:15 -04001529 qc = ata_qc_from_tag(ap, tag);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001530
1531 /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
1532 * bits (WARNING: might not necessarily be associated
1533 * with this command), which -should- be clear
1534 * if all is well
1535 */
1536 status = le16_to_cpu(pp->crpb[out_index].flags);
1537 if (unlikely(status & 0xff)) {
1538 mv_err_intr(ap, qc);
1539 return;
1540 }
1541
1542 /* and finally, complete the ATA command */
1543 if (qc) {
1544 qc->err_mask |=
1545 ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
1546 ata_qc_complete(qc);
1547 }
1548
Jeff Garzik0ea9e172007-07-13 17:06:45 -04001549 /* advance software response queue pointer, to
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001550 * indicate (after the loop completes) to hardware
1551 * that we have consumed a response queue entry.
1552 */
1553 work_done = true;
1554 pp->resp_idx++;
1555 }
1556
1557 if (work_done)
1558 writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
1559 (out_index << EDMA_RSP_Q_PTR_SHIFT),
1560 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04001561}
1562
Brett Russ05b308e2005-10-05 17:08:53 -04001563/**
1564 * mv_host_intr - Handle all interrupts on the given host controller
Jeff Garzikcca39742006-08-24 03:19:22 -04001565 * @host: host specific structure
Brett Russ05b308e2005-10-05 17:08:53 -04001566 * @relevant: port error bits relevant to this host controller
1567 * @hc: which host controller we're to look at
1568 *
1569 * Read then write clear the HC interrupt status then walk each
1570 * port connected to the HC and see if it needs servicing. Port
1571 * success ints are reported in the HC interrupt status reg, the
1572 * port error ints are reported in the higher level main
1573 * interrupt status register and thus are passed in via the
1574 * 'relevant' argument.
1575 *
1576 * LOCKING:
1577 * Inherited from caller.
1578 */
Jeff Garzikcca39742006-08-24 03:19:22 -04001579static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
Brett Russ20f733e72005-09-01 18:26:17 -04001580{
Tejun Heo0d5ff562007-02-01 15:06:36 +09001581 void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
Brett Russ20f733e72005-09-01 18:26:17 -04001582 void __iomem *hc_mmio = mv_hc_base(mmio, hc);
Brett Russ20f733e72005-09-01 18:26:17 -04001583 u32 hc_irq_cause;
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001584 int port, port0;
Brett Russ20f733e72005-09-01 18:26:17 -04001585
Jeff Garzik35177262007-02-24 21:26:42 -05001586 if (hc == 0)
Brett Russ20f733e72005-09-01 18:26:17 -04001587 port0 = 0;
Jeff Garzik35177262007-02-24 21:26:42 -05001588 else
Brett Russ20f733e72005-09-01 18:26:17 -04001589 port0 = MV_PORTS_PER_HC;
Brett Russ20f733e72005-09-01 18:26:17 -04001590
1591 /* we'll need the HC success int register in most cases */
1592 hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001593 if (!hc_irq_cause)
1594 return;
1595
1596 writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04001597
1598 VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
1599 hc,relevant,hc_irq_cause);
1600
1601 for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
Jeff Garzikcca39742006-08-24 03:19:22 -04001602 struct ata_port *ap = host->ports[port];
Mark Lord63af2a52006-03-29 09:50:31 -05001603 struct mv_port_priv *pp = ap->private_data;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001604 int have_err_bits, hard_port, shift;
Jeff Garzik55d8ca42006-03-29 19:43:31 -05001605
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001606 if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
Jeff Garzika2c91a82005-11-17 05:44:44 -05001607 continue;
1608
Brett Russ31961942005-09-30 01:36:00 -04001609 shift = port << 1; /* (port * 2) */
Brett Russ20f733e72005-09-01 18:26:17 -04001610 if (port >= MV_PORTS_PER_HC) {
1611 shift++; /* skip bit 8 in the HC Main IRQ reg */
1612 }
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001613 have_err_bits = ((PORT0_ERR << shift) & relevant);
1614
1615 if (unlikely(have_err_bits)) {
1616 struct ata_queued_cmd *qc;
1617
1618 qc = ata_qc_from_tag(ap, ap->active_tag);
1619 if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
1620 continue;
1621
1622 mv_err_intr(ap, qc);
1623 continue;
Brett Russ20f733e72005-09-01 18:26:17 -04001624 }
Jeff Garzik8b260242005-11-12 12:32:50 -05001625
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001626 hard_port = mv_hardport_from_port(port); /* range 0..3 */
1627
1628 if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
1629 if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
1630 mv_intr_edma(ap);
1631 } else {
1632 if ((DEV_IRQ << hard_port) & hc_irq_cause)
1633 mv_intr_pio(ap);
Brett Russ20f733e72005-09-01 18:26:17 -04001634 }
1635 }
1636 VPRINTK("EXIT\n");
1637}
1638
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001639static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
1640{
1641 struct ata_port *ap;
1642 struct ata_queued_cmd *qc;
1643 struct ata_eh_info *ehi;
1644 unsigned int i, err_mask, printed = 0;
1645 u32 err_cause;
1646
1647 err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS);
1648
1649 dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
1650 err_cause);
1651
1652 DPRINTK("All regs @ PCI error\n");
1653 mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
1654
1655 writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
1656
1657 for (i = 0; i < host->n_ports; i++) {
1658 ap = host->ports[i];
1659 if (!ata_port_offline(ap)) {
1660 ehi = &ap->eh_info;
1661 ata_ehi_clear_desc(ehi);
1662 if (!printed++)
1663 ata_ehi_push_desc(ehi,
1664 "PCI err cause 0x%08x", err_cause);
1665 err_mask = AC_ERR_HOST_BUS;
1666 ehi->action = ATA_EH_HARDRESET;
1667 qc = ata_qc_from_tag(ap, ap->active_tag);
1668 if (qc)
1669 qc->err_mask |= err_mask;
1670 else
1671 ehi->err_mask |= err_mask;
1672
1673 ata_port_freeze(ap);
1674 }
1675 }
1676}
1677
Brett Russ05b308e2005-10-05 17:08:53 -04001678/**
Jeff Garzikc5d3e452007-07-11 18:30:50 -04001679 * mv_interrupt - Main interrupt event handler
Brett Russ05b308e2005-10-05 17:08:53 -04001680 * @irq: unused
1681 * @dev_instance: private data; in this case the host structure
Brett Russ05b308e2005-10-05 17:08:53 -04001682 *
1683 * Read the read only register to determine if any host
1684 * controllers have pending interrupts. If so, call lower level
1685 * routine to handle. Also check for PCI errors which are only
1686 * reported here.
1687 *
Jeff Garzik8b260242005-11-12 12:32:50 -05001688 * LOCKING:
Jeff Garzikcca39742006-08-24 03:19:22 -04001689 * This routine holds the host lock while processing pending
Brett Russ05b308e2005-10-05 17:08:53 -04001690 * interrupts.
1691 */
David Howells7d12e782006-10-05 14:55:46 +01001692static irqreturn_t mv_interrupt(int irq, void *dev_instance)
Brett Russ20f733e72005-09-01 18:26:17 -04001693{
Jeff Garzikcca39742006-08-24 03:19:22 -04001694 struct ata_host *host = dev_instance;
Brett Russ20f733e72005-09-01 18:26:17 -04001695 unsigned int hc, handled = 0, n_hcs;
Tejun Heo0d5ff562007-02-01 15:06:36 +09001696 void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
Brett Russ20f733e72005-09-01 18:26:17 -04001697 u32 irq_stat;
1698
Brett Russ20f733e72005-09-01 18:26:17 -04001699 irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04001700
1701 /* check the cases where we either have nothing pending or have read
1702 * a bogus register value which can indicate HW removal or PCI fault
1703 */
Jeff Garzik35177262007-02-24 21:26:42 -05001704 if (!irq_stat || (0xffffffffU == irq_stat))
Brett Russ20f733e72005-09-01 18:26:17 -04001705 return IRQ_NONE;
Brett Russ20f733e72005-09-01 18:26:17 -04001706
Jeff Garzikcca39742006-08-24 03:19:22 -04001707 n_hcs = mv_get_hc_count(host->ports[0]->flags);
1708 spin_lock(&host->lock);
Brett Russ20f733e72005-09-01 18:26:17 -04001709
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001710 if (unlikely(irq_stat & PCI_ERR)) {
1711 mv_pci_error(host, mmio);
1712 handled = 1;
1713 goto out_unlock; /* skip all other HC irq handling */
1714 }
1715
Brett Russ20f733e72005-09-01 18:26:17 -04001716 for (hc = 0; hc < n_hcs; hc++) {
1717 u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
1718 if (relevant) {
Jeff Garzikcca39742006-08-24 03:19:22 -04001719 mv_host_intr(host, relevant, hc);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001720 handled = 1;
Brett Russ20f733e72005-09-01 18:26:17 -04001721 }
1722 }
Mark Lord615ab952006-05-19 16:24:56 -04001723
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04001724out_unlock:
Jeff Garzikcca39742006-08-24 03:19:22 -04001725 spin_unlock(&host->lock);
Brett Russ20f733e72005-09-01 18:26:17 -04001726
1727 return IRQ_RETVAL(handled);
1728}
1729
Jeff Garzikc9d39132005-11-13 17:47:51 -05001730static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
1731{
1732 void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
1733 unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
1734
1735 return hc_mmio + ofs;
1736}
1737
1738static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
1739{
1740 unsigned int ofs;
1741
1742 switch (sc_reg_in) {
1743 case SCR_STATUS:
1744 case SCR_ERROR:
1745 case SCR_CONTROL:
1746 ofs = sc_reg_in * sizeof(u32);
1747 break;
1748 default:
1749 ofs = 0xffffffffU;
1750 break;
1751 }
1752 return ofs;
1753}
1754
1755static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
1756{
Tejun Heo0d5ff562007-02-01 15:06:36 +09001757 void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
1758 void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
Jeff Garzikc9d39132005-11-13 17:47:51 -05001759 unsigned int ofs = mv5_scr_offset(sc_reg_in);
1760
1761 if (ofs != 0xffffffffU)
Tejun Heo0d5ff562007-02-01 15:06:36 +09001762 return readl(addr + ofs);
Jeff Garzikc9d39132005-11-13 17:47:51 -05001763 else
1764 return (u32) ofs;
1765}
1766
1767static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1768{
Tejun Heo0d5ff562007-02-01 15:06:36 +09001769 void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
1770 void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
Jeff Garzikc9d39132005-11-13 17:47:51 -05001771 unsigned int ofs = mv5_scr_offset(sc_reg_in);
1772
1773 if (ofs != 0xffffffffU)
Tejun Heo0d5ff562007-02-01 15:06:36 +09001774 writelfl(val, addr + ofs);
Jeff Garzikc9d39132005-11-13 17:47:51 -05001775}
1776
Jeff Garzik522479f2005-11-12 22:14:02 -05001777static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
1778{
Jeff Garzik522479f2005-11-12 22:14:02 -05001779 int early_5080;
1780
Auke Kok44c10132007-06-08 15:46:36 -07001781 early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
Jeff Garzik522479f2005-11-12 22:14:02 -05001782
1783 if (!early_5080) {
1784 u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1785 tmp |= (1 << 0);
1786 writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
1787 }
1788
1789 mv_reset_pci_bus(pdev, mmio);
1790}
1791
1792static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1793{
1794 writel(0x0fcfffff, mmio + MV_FLASH_CTL);
1795}
1796
Jeff Garzik47c2b672005-11-12 21:13:17 -05001797static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05001798 void __iomem *mmio)
1799{
Jeff Garzikc9d39132005-11-13 17:47:51 -05001800 void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
1801 u32 tmp;
1802
1803 tmp = readl(phy_mmio + MV5_PHY_MODE);
1804
1805 hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
1806 hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05001807}
1808
Jeff Garzik47c2b672005-11-12 21:13:17 -05001809static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05001810{
Jeff Garzik522479f2005-11-12 22:14:02 -05001811 u32 tmp;
1812
1813 writel(0, mmio + MV_GPIO_PORT_CTL);
1814
1815 /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
1816
1817 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
1818 tmp |= ~(1 << 0);
1819 writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05001820}
1821
Jeff Garzik2a47ce02005-11-12 23:05:14 -05001822static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
1823 unsigned int port)
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05001824{
Jeff Garzikc9d39132005-11-13 17:47:51 -05001825 void __iomem *phy_mmio = mv5_phy_base(mmio, port);
1826 const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
1827 u32 tmp;
1828 int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
1829
1830 if (fix_apm_sq) {
1831 tmp = readl(phy_mmio + MV5_LT_MODE);
1832 tmp |= (1 << 19);
1833 writel(tmp, phy_mmio + MV5_LT_MODE);
1834
1835 tmp = readl(phy_mmio + MV5_PHY_CTL);
1836 tmp &= ~0x3;
1837 tmp |= 0x1;
1838 writel(tmp, phy_mmio + MV5_PHY_CTL);
1839 }
1840
1841 tmp = readl(phy_mmio + MV5_PHY_MODE);
1842 tmp &= ~mask;
1843 tmp |= hpriv->signal[port].pre;
1844 tmp |= hpriv->signal[port].amps;
1845 writel(tmp, phy_mmio + MV5_PHY_MODE);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05001846}
1847
Jeff Garzikc9d39132005-11-13 17:47:51 -05001848
1849#undef ZERO
1850#define ZERO(reg) writel(0, port_mmio + (reg))
1851static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
1852 unsigned int port)
Jeff Garzik47c2b672005-11-12 21:13:17 -05001853{
Jeff Garzikc9d39132005-11-13 17:47:51 -05001854 void __iomem *port_mmio = mv_port_base(mmio, port);
1855
1856 writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
1857
1858 mv_channel_reset(hpriv, mmio, port);
1859
1860 ZERO(0x028); /* command */
1861 writel(0x11f, port_mmio + EDMA_CFG_OFS);
1862 ZERO(0x004); /* timer */
1863 ZERO(0x008); /* irq err cause */
1864 ZERO(0x00c); /* irq err mask */
1865 ZERO(0x010); /* rq bah */
1866 ZERO(0x014); /* rq inp */
1867 ZERO(0x018); /* rq outp */
1868 ZERO(0x01c); /* respq bah */
1869 ZERO(0x024); /* respq outp */
1870 ZERO(0x020); /* respq inp */
1871 ZERO(0x02c); /* test control */
1872 writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
1873}
1874#undef ZERO
1875
1876#define ZERO(reg) writel(0, hc_mmio + (reg))
1877static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1878 unsigned int hc)
1879{
1880 void __iomem *hc_mmio = mv_hc_base(mmio, hc);
1881 u32 tmp;
1882
1883 ZERO(0x00c);
1884 ZERO(0x010);
1885 ZERO(0x014);
1886 ZERO(0x018);
1887
1888 tmp = readl(hc_mmio + 0x20);
1889 tmp &= 0x1c1c1c1c;
1890 tmp |= 0x03030303;
1891 writel(tmp, hc_mmio + 0x20);
1892}
1893#undef ZERO
1894
1895static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1896 unsigned int n_hc)
1897{
1898 unsigned int hc, port;
1899
1900 for (hc = 0; hc < n_hc; hc++) {
1901 for (port = 0; port < MV_PORTS_PER_HC; port++)
1902 mv5_reset_hc_port(hpriv, mmio,
1903 (hc * MV_PORTS_PER_HC) + port);
1904
1905 mv5_reset_one_hc(hpriv, mmio, hc);
1906 }
1907
1908 return 0;
Jeff Garzik47c2b672005-11-12 21:13:17 -05001909}
1910
Jeff Garzik101ffae2005-11-12 22:17:49 -05001911#undef ZERO
1912#define ZERO(reg) writel(0, mmio + (reg))
1913static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
1914{
1915 u32 tmp;
1916
1917 tmp = readl(mmio + MV_PCI_MODE);
1918 tmp &= 0xff00ffff;
1919 writel(tmp, mmio + MV_PCI_MODE);
1920
1921 ZERO(MV_PCI_DISC_TIMER);
1922 ZERO(MV_PCI_MSI_TRIGGER);
1923 writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
1924 ZERO(HC_MAIN_IRQ_MASK_OFS);
1925 ZERO(MV_PCI_SERR_MASK);
1926 ZERO(PCI_IRQ_CAUSE_OFS);
1927 ZERO(PCI_IRQ_MASK_OFS);
1928 ZERO(MV_PCI_ERR_LOW_ADDRESS);
1929 ZERO(MV_PCI_ERR_HIGH_ADDRESS);
1930 ZERO(MV_PCI_ERR_ATTRIBUTE);
1931 ZERO(MV_PCI_ERR_COMMAND);
1932}
1933#undef ZERO
1934
1935static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
1936{
1937 u32 tmp;
1938
1939 mv5_reset_flash(hpriv, mmio);
1940
1941 tmp = readl(mmio + MV_GPIO_PORT_CTL);
1942 tmp &= 0x3;
1943 tmp |= (1 << 5) | (1 << 6);
1944 writel(tmp, mmio + MV_GPIO_PORT_CTL);
1945}
1946
1947/**
1948 * mv6_reset_hc - Perform the 6xxx global soft reset
1949 * @mmio: base address of the HBA
1950 *
1951 * This routine only applies to 6xxx parts.
1952 *
1953 * LOCKING:
1954 * Inherited from caller.
1955 */
Jeff Garzikc9d39132005-11-13 17:47:51 -05001956static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
1957 unsigned int n_hc)
Jeff Garzik101ffae2005-11-12 22:17:49 -05001958{
1959 void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
1960 int i, rc = 0;
1961 u32 t;
1962
1963 /* Following procedure defined in PCI "main command and status
1964 * register" table.
1965 */
1966 t = readl(reg);
1967 writel(t | STOP_PCI_MASTER, reg);
1968
1969 for (i = 0; i < 1000; i++) {
1970 udelay(1);
1971 t = readl(reg);
1972 if (PCI_MASTER_EMPTY & t) {
1973 break;
1974 }
1975 }
1976 if (!(PCI_MASTER_EMPTY & t)) {
1977 printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
1978 rc = 1;
1979 goto done;
1980 }
1981
1982 /* set reset */
1983 i = 5;
1984 do {
1985 writel(t | GLOB_SFT_RST, reg);
1986 t = readl(reg);
1987 udelay(1);
1988 } while (!(GLOB_SFT_RST & t) && (i-- > 0));
1989
1990 if (!(GLOB_SFT_RST & t)) {
1991 printk(KERN_ERR DRV_NAME ": can't set global reset\n");
1992 rc = 1;
1993 goto done;
1994 }
1995
1996 /* clear reset and *reenable the PCI master* (not mentioned in spec) */
1997 i = 5;
1998 do {
1999 writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
2000 t = readl(reg);
2001 udelay(1);
2002 } while ((GLOB_SFT_RST & t) && (i-- > 0));
2003
2004 if (GLOB_SFT_RST & t) {
2005 printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
2006 rc = 1;
2007 }
2008done:
2009 return rc;
2010}
2011
Jeff Garzik47c2b672005-11-12 21:13:17 -05002012static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05002013 void __iomem *mmio)
2014{
2015 void __iomem *port_mmio;
2016 u32 tmp;
2017
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05002018 tmp = readl(mmio + MV_RESET_CFG);
2019 if ((tmp & (1 << 0)) == 0) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002020 hpriv->signal[idx].amps = 0x7 << 8;
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05002021 hpriv->signal[idx].pre = 0x1 << 5;
2022 return;
2023 }
2024
2025 port_mmio = mv_port_base(mmio, idx);
2026 tmp = readl(port_mmio + PHY_MODE2);
2027
2028 hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
2029 hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
2030}
2031
Jeff Garzik47c2b672005-11-12 21:13:17 -05002032static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05002033{
Jeff Garzik47c2b672005-11-12 21:13:17 -05002034 writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
Jeff Garzikba3fe8f2005-11-12 19:08:48 -05002035}
2036
Jeff Garzikc9d39132005-11-13 17:47:51 -05002037static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002038 unsigned int port)
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002039{
Jeff Garzikc9d39132005-11-13 17:47:51 -05002040 void __iomem *port_mmio = mv_port_base(mmio, port);
2041
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002042 u32 hp_flags = hpriv->hp_flags;
Jeff Garzik47c2b672005-11-12 21:13:17 -05002043 int fix_phy_mode2 =
2044 hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002045 int fix_phy_mode4 =
Jeff Garzik47c2b672005-11-12 21:13:17 -05002046 hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
2047 u32 m2, tmp;
2048
2049 if (fix_phy_mode2) {
2050 m2 = readl(port_mmio + PHY_MODE2);
2051 m2 &= ~(1 << 16);
2052 m2 |= (1 << 31);
2053 writel(m2, port_mmio + PHY_MODE2);
2054
2055 udelay(200);
2056
2057 m2 = readl(port_mmio + PHY_MODE2);
2058 m2 &= ~((1 << 16) | (1 << 31));
2059 writel(m2, port_mmio + PHY_MODE2);
2060
2061 udelay(200);
2062 }
2063
2064 /* who knows what this magic does */
2065 tmp = readl(port_mmio + PHY_MODE3);
2066 tmp &= ~0x7F800000;
2067 tmp |= 0x2A800000;
2068 writel(tmp, port_mmio + PHY_MODE3);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002069
2070 if (fix_phy_mode4) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002071 u32 m4;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002072
2073 m4 = readl(port_mmio + PHY_MODE4);
Jeff Garzik47c2b672005-11-12 21:13:17 -05002074
2075 if (hp_flags & MV_HP_ERRATA_60X1B2)
2076 tmp = readl(port_mmio + 0x310);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002077
2078 m4 = (m4 & ~(1 << 1)) | (1 << 0);
2079
2080 writel(m4, port_mmio + PHY_MODE4);
Jeff Garzik47c2b672005-11-12 21:13:17 -05002081
2082 if (hp_flags & MV_HP_ERRATA_60X1B2)
2083 writel(tmp, port_mmio + 0x310);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002084 }
2085
2086 /* Revert values of pre-emphasis and signal amps to the saved ones */
2087 m2 = readl(port_mmio + PHY_MODE2);
2088
2089 m2 &= ~MV_M2_PREAMP_MASK;
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002090 m2 |= hpriv->signal[port].amps;
2091 m2 |= hpriv->signal[port].pre;
Jeff Garzik47c2b672005-11-12 21:13:17 -05002092 m2 &= ~(1 << 16);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002093
Jeff Garzike4e7b892006-01-31 12:18:41 -05002094 /* according to mvSata 3.6.1, some IIE values are fixed */
2095 if (IS_GEN_IIE(hpriv)) {
2096 m2 &= ~0xC30FF01F;
2097 m2 |= 0x0000900F;
2098 }
2099
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002100 writel(m2, port_mmio + PHY_MODE2);
2101}
2102
Jeff Garzikc9d39132005-11-13 17:47:51 -05002103static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
2104 unsigned int port_no)
Brett Russ20f733e72005-09-01 18:26:17 -04002105{
Jeff Garzikc9d39132005-11-13 17:47:51 -05002106 void __iomem *port_mmio = mv_port_base(mmio, port_no);
Brett Russ20f733e72005-09-01 18:26:17 -04002107
Brett Russ31961942005-09-30 01:36:00 -04002108 writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002109
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002110 if (IS_GEN_II(hpriv)) {
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002111 u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
Mark Lordeb46d682006-05-19 16:29:21 -04002112 ifctl |= (1 << 7); /* enable gen2i speed */
2113 ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002114 writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2115 }
2116
Brett Russ20f733e72005-09-01 18:26:17 -04002117 udelay(25); /* allow reset propagation */
2118
2119 /* Spec never mentions clearing the bit. Marvell's driver does
2120 * clear the bit, however.
2121 */
Brett Russ31961942005-09-30 01:36:00 -04002122 writelfl(0, port_mmio + EDMA_CMD_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04002123
Jeff Garzikc9d39132005-11-13 17:47:51 -05002124 hpriv->ops->phy_errata(hpriv, mmio, port_no);
2125
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002126 if (IS_GEN_I(hpriv))
Jeff Garzikc9d39132005-11-13 17:47:51 -05002127 mdelay(1);
2128}
2129
Jeff Garzikc9d39132005-11-13 17:47:51 -05002130/**
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002131 * mv_phy_reset - Perform eDMA reset followed by COMRESET
Jeff Garzikc9d39132005-11-13 17:47:51 -05002132 * @ap: ATA channel to manipulate
2133 *
2134 * Part of this is taken from __sata_phy_reset and modified to
2135 * not sleep since this routine gets called from interrupt level.
2136 *
2137 * LOCKING:
2138 * Inherited from caller. This is coded to safe to call at
2139 * interrupt level, i.e. it does not sleep.
2140 */
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002141static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
2142 unsigned long deadline)
Jeff Garzikc9d39132005-11-13 17:47:51 -05002143{
2144 struct mv_port_priv *pp = ap->private_data;
Jeff Garzikcca39742006-08-24 03:19:22 -04002145 struct mv_host_priv *hpriv = ap->host->private_data;
Jeff Garzikc9d39132005-11-13 17:47:51 -05002146 void __iomem *port_mmio = mv_ap_base(ap);
Jeff Garzik22374672005-11-17 10:59:48 -05002147 int retry = 5;
2148 u32 sstatus;
Jeff Garzikc9d39132005-11-13 17:47:51 -05002149
2150 VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002151
Jeff Garzik095fec82005-11-12 09:50:49 -05002152 DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
Brett Russ31961942005-09-30 01:36:00 -04002153 "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
2154 mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
Brett Russ20f733e72005-09-01 18:26:17 -04002155
Jeff Garzik22374672005-11-17 10:59:48 -05002156 /* Issue COMRESET via SControl */
2157comreset_retry:
Tejun Heo81952c52006-05-15 20:57:47 +09002158 sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002159 msleep(1);
Jeff Garzik22374672005-11-17 10:59:48 -05002160
Tejun Heo81952c52006-05-15 20:57:47 +09002161 sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002162 msleep(20);
Jeff Garzik22374672005-11-17 10:59:48 -05002163
Brett Russ31961942005-09-30 01:36:00 -04002164 do {
Tejun Heo81952c52006-05-15 20:57:47 +09002165 sata_scr_read(ap, SCR_STATUS, &sstatus);
Andres Salomon62f1d0e2006-09-11 08:51:05 -04002166 if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
Brett Russ31961942005-09-30 01:36:00 -04002167 break;
Jeff Garzik22374672005-11-17 10:59:48 -05002168
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002169 msleep(1);
Jeff Garzikc5d3e452007-07-11 18:30:50 -04002170 } while (time_before(jiffies, deadline));
Brett Russ20f733e72005-09-01 18:26:17 -04002171
Jeff Garzik22374672005-11-17 10:59:48 -05002172 /* work around errata */
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002173 if (IS_GEN_II(hpriv) &&
Jeff Garzik22374672005-11-17 10:59:48 -05002174 (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
2175 (retry-- > 0))
2176 goto comreset_retry;
Jeff Garzik095fec82005-11-12 09:50:49 -05002177
2178 DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
Brett Russ31961942005-09-30 01:36:00 -04002179 "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
2180 mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
2181
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002182 if (ata_port_offline(ap)) {
2183 *class = ATA_DEV_NONE;
Brett Russ20f733e72005-09-01 18:26:17 -04002184 return;
2185 }
2186
Jeff Garzik22374672005-11-17 10:59:48 -05002187 /* even after SStatus reflects that device is ready,
2188 * it seems to take a while for link to be fully
2189 * established (and thus Status no longer 0x80/0x7F),
2190 * so we poll a bit for that, here.
2191 */
2192 retry = 20;
2193 while (1) {
2194 u8 drv_stat = ata_check_status(ap);
2195 if ((drv_stat != 0x80) && (drv_stat != 0x7f))
2196 break;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002197 msleep(500);
Jeff Garzik22374672005-11-17 10:59:48 -05002198 if (retry-- <= 0)
2199 break;
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002200 if (time_after(jiffies, deadline))
2201 break;
Jeff Garzik22374672005-11-17 10:59:48 -05002202 }
2203
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002204 /* FIXME: if we passed the deadline, the following
2205 * code probably produces an invalid result
2206 */
Brett Russ20f733e72005-09-01 18:26:17 -04002207
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002208 /* finally, read device signature from TF registers */
2209 *class = ata_dev_try_classify(ap, 0, NULL);
Jeff Garzik095fec82005-11-12 09:50:49 -05002210
2211 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2212
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002213 WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
Jeff Garzik095fec82005-11-12 09:50:49 -05002214
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002215 VPRINTK("EXIT\n");
Brett Russ20f733e72005-09-01 18:26:17 -04002216}
2217
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002218static int mv_prereset(struct ata_port *ap, unsigned long deadline)
Jeff Garzik22374672005-11-17 10:59:48 -05002219{
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002220 struct mv_port_priv *pp = ap->private_data;
2221 struct ata_eh_context *ehc = &ap->eh_context;
2222 int rc;
Jeff Garzik0ea9e172007-07-13 17:06:45 -04002223
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002224 rc = mv_stop_dma(ap);
2225 if (rc)
2226 ehc->i.action |= ATA_EH_HARDRESET;
2227
2228 if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) {
2229 pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
2230 ehc->i.action |= ATA_EH_HARDRESET;
2231 }
2232
2233 /* if we're about to do hardreset, nothing more to do */
2234 if (ehc->i.action & ATA_EH_HARDRESET)
2235 return 0;
2236
2237 if (ata_port_online(ap))
2238 rc = ata_wait_ready(ap, deadline);
2239 else
2240 rc = -ENODEV;
2241
2242 return rc;
Jeff Garzik22374672005-11-17 10:59:48 -05002243}
2244
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002245static int mv_hardreset(struct ata_port *ap, unsigned int *class,
2246 unsigned long deadline)
2247{
2248 struct mv_host_priv *hpriv = ap->host->private_data;
2249 void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2250
2251 mv_stop_dma(ap);
2252
2253 mv_channel_reset(hpriv, mmio, ap->port_no);
2254
2255 mv_phy_reset(ap, class, deadline);
2256
2257 return 0;
2258}
2259
2260static void mv_postreset(struct ata_port *ap, unsigned int *classes)
2261{
2262 u32 serr;
2263
2264 /* print link status */
2265 sata_print_link_status(ap);
2266
2267 /* clear SError */
2268 sata_scr_read(ap, SCR_ERROR, &serr);
2269 sata_scr_write_flush(ap, SCR_ERROR, serr);
2270
2271 /* bail out if no device is present */
2272 if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
2273 DPRINTK("EXIT, no device\n");
2274 return;
2275 }
2276
2277 /* set up device control */
2278 iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
2279}
2280
2281static void mv_error_handler(struct ata_port *ap)
2282{
2283 ata_do_eh(ap, mv_prereset, ata_std_softreset,
2284 mv_hardreset, mv_postreset);
2285}
2286
2287static void mv_post_int_cmd(struct ata_queued_cmd *qc)
2288{
2289 mv_stop_dma(qc->ap);
2290}
2291
2292static void mv_eh_freeze(struct ata_port *ap)
Brett Russ20f733e72005-09-01 18:26:17 -04002293{
Tejun Heo0d5ff562007-02-01 15:06:36 +09002294 void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002295 unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2296 u32 tmp, mask;
2297 unsigned int shift;
Brett Russ31961942005-09-30 01:36:00 -04002298
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002299 /* FIXME: handle coalescing completion events properly */
Brett Russ31961942005-09-30 01:36:00 -04002300
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002301 shift = ap->port_no * 2;
2302 if (hc > 0)
2303 shift++;
Brett Russ31961942005-09-30 01:36:00 -04002304
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002305 mask = 0x3 << shift;
Brett Russ31961942005-09-30 01:36:00 -04002306
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002307 /* disable assertion of portN err, done events */
2308 tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2309 writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
2310}
2311
2312static void mv_eh_thaw(struct ata_port *ap)
2313{
2314 void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
2315 unsigned int hc = (ap->port_no > 3) ? 1 : 0;
2316 void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2317 void __iomem *port_mmio = mv_ap_base(ap);
2318 u32 tmp, mask, hc_irq_cause;
2319 unsigned int shift, hc_port_no = ap->port_no;
2320
2321 /* FIXME: handle coalescing completion events properly */
2322
2323 shift = ap->port_no * 2;
2324 if (hc > 0) {
2325 shift++;
2326 hc_port_no -= 4;
Mark Lord9b358e32006-05-19 16:21:03 -04002327 }
Jeff Garzikbdd4ddd2007-07-12 14:34:26 -04002328
2329 mask = 0x3 << shift;
2330
2331 /* clear EDMA errors on this port */
2332 writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2333
2334 /* clear pending irq events */
2335 hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
2336 hc_irq_cause &= ~(1 << hc_port_no); /* clear CRPB-done */
2337 hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
2338 writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
2339
2340 /* enable assertion of portN err, done events */
2341 tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
2342 writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
Brett Russ31961942005-09-30 01:36:00 -04002343}
2344
Brett Russ05b308e2005-10-05 17:08:53 -04002345/**
2346 * mv_port_init - Perform some early initialization on a single port.
2347 * @port: libata data structure storing shadow register addresses
2348 * @port_mmio: base address of the port
2349 *
2350 * Initialize shadow register mmio addresses, clear outstanding
2351 * interrupts on the port, and unmask interrupts for the future
2352 * start of the port.
2353 *
2354 * LOCKING:
2355 * Inherited from caller.
2356 */
Brett Russ31961942005-09-30 01:36:00 -04002357static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
2358{
Tejun Heo0d5ff562007-02-01 15:06:36 +09002359 void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
Brett Russ31961942005-09-30 01:36:00 -04002360 unsigned serr_ofs;
2361
Jeff Garzik8b260242005-11-12 12:32:50 -05002362 /* PIO related setup
Brett Russ31961942005-09-30 01:36:00 -04002363 */
2364 port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
Jeff Garzik8b260242005-11-12 12:32:50 -05002365 port->error_addr =
Brett Russ31961942005-09-30 01:36:00 -04002366 port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
2367 port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
2368 port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
2369 port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
2370 port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
2371 port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
Jeff Garzik8b260242005-11-12 12:32:50 -05002372 port->status_addr =
Brett Russ31961942005-09-30 01:36:00 -04002373 port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
2374 /* special case: control/altstatus doesn't have ATA_REG_ address */
2375 port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
2376
2377 /* unused: */
Randy Dunlap8d9db2d2007-02-16 01:40:06 -08002378 port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
Brett Russ20f733e72005-09-01 18:26:17 -04002379
Brett Russ31961942005-09-30 01:36:00 -04002380 /* Clear any currently outstanding port interrupt conditions */
2381 serr_ofs = mv_scr_offset(SCR_ERROR);
2382 writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
2383 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
2384
Brett Russ20f733e72005-09-01 18:26:17 -04002385 /* unmask all EDMA error interrupts */
Brett Russ31961942005-09-30 01:36:00 -04002386 writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04002387
Jeff Garzik8b260242005-11-12 12:32:50 -05002388 VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
Brett Russ31961942005-09-30 01:36:00 -04002389 readl(port_mmio + EDMA_CFG_OFS),
2390 readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
2391 readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
Brett Russ20f733e72005-09-01 18:26:17 -04002392}
2393
Tejun Heo4447d352007-04-17 23:44:08 +09002394static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002395{
Tejun Heo4447d352007-04-17 23:44:08 +09002396 struct pci_dev *pdev = to_pci_dev(host->dev);
2397 struct mv_host_priv *hpriv = host->private_data;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002398 u32 hp_flags = hpriv->hp_flags;
2399
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002400 switch(board_idx) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002401 case chip_5080:
2402 hpriv->ops = &mv5xxx_ops;
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002403 hp_flags |= MV_HP_GEN_I;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002404
Auke Kok44c10132007-06-08 15:46:36 -07002405 switch (pdev->revision) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002406 case 0x1:
2407 hp_flags |= MV_HP_ERRATA_50XXB0;
2408 break;
2409 case 0x3:
2410 hp_flags |= MV_HP_ERRATA_50XXB2;
2411 break;
2412 default:
2413 dev_printk(KERN_WARNING, &pdev->dev,
2414 "Applying 50XXB2 workarounds to unknown rev\n");
2415 hp_flags |= MV_HP_ERRATA_50XXB2;
2416 break;
2417 }
2418 break;
2419
2420 case chip_504x:
2421 case chip_508x:
2422 hpriv->ops = &mv5xxx_ops;
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002423 hp_flags |= MV_HP_GEN_I;
Jeff Garzik47c2b672005-11-12 21:13:17 -05002424
Auke Kok44c10132007-06-08 15:46:36 -07002425 switch (pdev->revision) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002426 case 0x0:
2427 hp_flags |= MV_HP_ERRATA_50XXB0;
2428 break;
2429 case 0x3:
2430 hp_flags |= MV_HP_ERRATA_50XXB2;
2431 break;
2432 default:
2433 dev_printk(KERN_WARNING, &pdev->dev,
2434 "Applying B2 workarounds to unknown rev\n");
2435 hp_flags |= MV_HP_ERRATA_50XXB2;
2436 break;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002437 }
2438 break;
2439
2440 case chip_604x:
2441 case chip_608x:
Jeff Garzik47c2b672005-11-12 21:13:17 -05002442 hpriv->ops = &mv6xxx_ops;
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002443 hp_flags |= MV_HP_GEN_II;
Jeff Garzik47c2b672005-11-12 21:13:17 -05002444
Auke Kok44c10132007-06-08 15:46:36 -07002445 switch (pdev->revision) {
Jeff Garzik47c2b672005-11-12 21:13:17 -05002446 case 0x7:
2447 hp_flags |= MV_HP_ERRATA_60X1B2;
2448 break;
2449 case 0x9:
2450 hp_flags |= MV_HP_ERRATA_60X1C0;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002451 break;
2452 default:
2453 dev_printk(KERN_WARNING, &pdev->dev,
Jeff Garzik47c2b672005-11-12 21:13:17 -05002454 "Applying B2 workarounds to unknown rev\n");
2455 hp_flags |= MV_HP_ERRATA_60X1B2;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002456 break;
2457 }
2458 break;
2459
Jeff Garzike4e7b892006-01-31 12:18:41 -05002460 case chip_7042:
2461 case chip_6042:
2462 hpriv->ops = &mv6xxx_ops;
Jeff Garzike4e7b892006-01-31 12:18:41 -05002463 hp_flags |= MV_HP_GEN_IIE;
2464
Auke Kok44c10132007-06-08 15:46:36 -07002465 switch (pdev->revision) {
Jeff Garzike4e7b892006-01-31 12:18:41 -05002466 case 0x0:
2467 hp_flags |= MV_HP_ERRATA_XX42A0;
2468 break;
2469 case 0x1:
2470 hp_flags |= MV_HP_ERRATA_60X1C0;
2471 break;
2472 default:
2473 dev_printk(KERN_WARNING, &pdev->dev,
2474 "Applying 60X1C0 workarounds to unknown rev\n");
2475 hp_flags |= MV_HP_ERRATA_60X1C0;
2476 break;
2477 }
2478 break;
2479
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002480 default:
2481 printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
2482 return 1;
2483 }
2484
2485 hpriv->hp_flags = hp_flags;
2486
2487 return 0;
2488}
2489
Brett Russ05b308e2005-10-05 17:08:53 -04002490/**
Jeff Garzik47c2b672005-11-12 21:13:17 -05002491 * mv_init_host - Perform some early initialization of the host.
Tejun Heo4447d352007-04-17 23:44:08 +09002492 * @host: ATA host to initialize
2493 * @board_idx: controller index
Brett Russ05b308e2005-10-05 17:08:53 -04002494 *
2495 * If possible, do an early global reset of the host. Then do
2496 * our port init and clear/unmask all/relevant host interrupts.
2497 *
2498 * LOCKING:
2499 * Inherited from caller.
2500 */
Tejun Heo4447d352007-04-17 23:44:08 +09002501static int mv_init_host(struct ata_host *host, unsigned int board_idx)
Brett Russ20f733e72005-09-01 18:26:17 -04002502{
2503 int rc = 0, n_hc, port, hc;
Tejun Heo4447d352007-04-17 23:44:08 +09002504 struct pci_dev *pdev = to_pci_dev(host->dev);
2505 void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
2506 struct mv_host_priv *hpriv = host->private_data;
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002507
Jeff Garzik47c2b672005-11-12 21:13:17 -05002508 /* global interrupt mask */
2509 writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
2510
Tejun Heo4447d352007-04-17 23:44:08 +09002511 rc = mv_chip_id(host, board_idx);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002512 if (rc)
2513 goto done;
2514
Tejun Heo4447d352007-04-17 23:44:08 +09002515 n_hc = mv_get_hc_count(host->ports[0]->flags);
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002516
Tejun Heo4447d352007-04-17 23:44:08 +09002517 for (port = 0; port < host->n_ports; port++)
Jeff Garzik47c2b672005-11-12 21:13:17 -05002518 hpriv->ops->read_preamp(hpriv, port, mmio);
Brett Russ20f733e72005-09-01 18:26:17 -04002519
Jeff Garzikc9d39132005-11-13 17:47:51 -05002520 rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
Jeff Garzik47c2b672005-11-12 21:13:17 -05002521 if (rc)
Brett Russ20f733e72005-09-01 18:26:17 -04002522 goto done;
Brett Russ20f733e72005-09-01 18:26:17 -04002523
Jeff Garzik522479f2005-11-12 22:14:02 -05002524 hpriv->ops->reset_flash(hpriv, mmio);
2525 hpriv->ops->reset_bus(pdev, mmio);
Jeff Garzik47c2b672005-11-12 21:13:17 -05002526 hpriv->ops->enable_leds(hpriv, mmio);
Brett Russ20f733e72005-09-01 18:26:17 -04002527
Tejun Heo4447d352007-04-17 23:44:08 +09002528 for (port = 0; port < host->n_ports; port++) {
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002529 if (IS_GEN_II(hpriv)) {
Jeff Garzikc9d39132005-11-13 17:47:51 -05002530 void __iomem *port_mmio = mv_port_base(mmio, port);
2531
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002532 u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
Mark Lordeb46d682006-05-19 16:29:21 -04002533 ifctl |= (1 << 7); /* enable gen2i speed */
2534 ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002535 writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
2536 }
2537
Jeff Garzikc9d39132005-11-13 17:47:51 -05002538 hpriv->ops->phy_errata(hpriv, mmio, port);
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002539 }
2540
Tejun Heo4447d352007-04-17 23:44:08 +09002541 for (port = 0; port < host->n_ports; port++) {
Jeff Garzik2a47ce02005-11-12 23:05:14 -05002542 void __iomem *port_mmio = mv_port_base(mmio, port);
Tejun Heo4447d352007-04-17 23:44:08 +09002543 mv_port_init(&host->ports[port]->ioaddr, port_mmio);
Brett Russ20f733e72005-09-01 18:26:17 -04002544 }
2545
2546 for (hc = 0; hc < n_hc; hc++) {
Brett Russ31961942005-09-30 01:36:00 -04002547 void __iomem *hc_mmio = mv_hc_base(mmio, hc);
2548
2549 VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
2550 "(before clear)=0x%08x\n", hc,
2551 readl(hc_mmio + HC_CFG_OFS),
2552 readl(hc_mmio + HC_IRQ_CAUSE_OFS));
2553
2554 /* Clear any currently outstanding hc interrupt conditions */
2555 writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04002556 }
2557
Brett Russ31961942005-09-30 01:36:00 -04002558 /* Clear any currently outstanding host interrupt conditions */
2559 writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
2560
2561 /* and unmask interrupt generation for host regs */
2562 writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
Jeff Garzikfb621e22007-02-25 04:19:45 -05002563
Jeff Garzikee9ccdf2007-07-12 15:51:22 -04002564 if (IS_GEN_I(hpriv))
Jeff Garzikfb621e22007-02-25 04:19:45 -05002565 writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
2566 else
2567 writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
Brett Russ20f733e72005-09-01 18:26:17 -04002568
2569 VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
Jeff Garzik8b260242005-11-12 12:32:50 -05002570 "PCI int cause/mask=0x%08x/0x%08x\n",
Brett Russ20f733e72005-09-01 18:26:17 -04002571 readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
2572 readl(mmio + HC_MAIN_IRQ_MASK_OFS),
2573 readl(mmio + PCI_IRQ_CAUSE_OFS),
2574 readl(mmio + PCI_IRQ_MASK_OFS));
Jeff Garzikbca1c4e2005-11-12 12:48:15 -05002575
Brett Russ31961942005-09-30 01:36:00 -04002576done:
Brett Russ20f733e72005-09-01 18:26:17 -04002577 return rc;
2578}
2579
Brett Russ05b308e2005-10-05 17:08:53 -04002580/**
2581 * mv_print_info - Dump key info to kernel log for perusal.
Tejun Heo4447d352007-04-17 23:44:08 +09002582 * @host: ATA host to print info about
Brett Russ05b308e2005-10-05 17:08:53 -04002583 *
2584 * FIXME: complete this.
2585 *
2586 * LOCKING:
2587 * Inherited from caller.
2588 */
Tejun Heo4447d352007-04-17 23:44:08 +09002589static void mv_print_info(struct ata_host *host)
Brett Russ31961942005-09-30 01:36:00 -04002590{
Tejun Heo4447d352007-04-17 23:44:08 +09002591 struct pci_dev *pdev = to_pci_dev(host->dev);
2592 struct mv_host_priv *hpriv = host->private_data;
Auke Kok44c10132007-06-08 15:46:36 -07002593 u8 scc;
Jeff Garzikc1e4fe72007-07-09 12:29:31 -04002594 const char *scc_s, *gen;
Brett Russ31961942005-09-30 01:36:00 -04002595
2596 /* Use this to determine the HW stepping of the chip so we know
2597 * what errata to workaround
2598 */
Brett Russ31961942005-09-30 01:36:00 -04002599 pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
2600 if (scc == 0)
2601 scc_s = "SCSI";
2602 else if (scc == 0x01)
2603 scc_s = "RAID";
2604 else
Jeff Garzikc1e4fe72007-07-09 12:29:31 -04002605 scc_s = "?";
2606
2607 if (IS_GEN_I(hpriv))
2608 gen = "I";
2609 else if (IS_GEN_II(hpriv))
2610 gen = "II";
2611 else if (IS_GEN_IIE(hpriv))
2612 gen = "IIE";
2613 else
2614 gen = "?";
Brett Russ31961942005-09-30 01:36:00 -04002615
Jeff Garzika9524a72005-10-30 14:39:11 -05002616 dev_printk(KERN_INFO, &pdev->dev,
Jeff Garzikc1e4fe72007-07-09 12:29:31 -04002617 "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
2618 gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
Brett Russ31961942005-09-30 01:36:00 -04002619 scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
2620}
2621
Brett Russ05b308e2005-10-05 17:08:53 -04002622/**
2623 * mv_init_one - handle a positive probe of a Marvell host
2624 * @pdev: PCI device found
2625 * @ent: PCI device ID entry for the matched host
2626 *
2627 * LOCKING:
2628 * Inherited from caller.
2629 */
Brett Russ20f733e72005-09-01 18:26:17 -04002630static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2631{
2632 static int printed_version = 0;
Brett Russ20f733e72005-09-01 18:26:17 -04002633 unsigned int board_idx = (unsigned int)ent->driver_data;
Tejun Heo4447d352007-04-17 23:44:08 +09002634 const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
2635 struct ata_host *host;
2636 struct mv_host_priv *hpriv;
2637 int n_ports, rc;
Brett Russ20f733e72005-09-01 18:26:17 -04002638
Jeff Garzika9524a72005-10-30 14:39:11 -05002639 if (!printed_version++)
2640 dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
Brett Russ20f733e72005-09-01 18:26:17 -04002641
Tejun Heo4447d352007-04-17 23:44:08 +09002642 /* allocate host */
2643 n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
2644
2645 host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
2646 hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
2647 if (!host || !hpriv)
2648 return -ENOMEM;
2649 host->private_data = hpriv;
2650
2651 /* acquire resources */
Tejun Heo24dc5f32007-01-20 16:00:28 +09002652 rc = pcim_enable_device(pdev);
2653 if (rc)
Brett Russ20f733e72005-09-01 18:26:17 -04002654 return rc;
Brett Russ20f733e72005-09-01 18:26:17 -04002655
Tejun Heo0d5ff562007-02-01 15:06:36 +09002656 rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
2657 if (rc == -EBUSY)
Tejun Heo24dc5f32007-01-20 16:00:28 +09002658 pcim_pin_device(pdev);
Tejun Heo0d5ff562007-02-01 15:06:36 +09002659 if (rc)
Tejun Heo24dc5f32007-01-20 16:00:28 +09002660 return rc;
Tejun Heo4447d352007-04-17 23:44:08 +09002661 host->iomap = pcim_iomap_table(pdev);
Brett Russ20f733e72005-09-01 18:26:17 -04002662
Jeff Garzikd88184f2007-02-26 01:26:06 -05002663 rc = pci_go_64(pdev);
2664 if (rc)
2665 return rc;
2666
Brett Russ20f733e72005-09-01 18:26:17 -04002667 /* initialize adapter */
Tejun Heo4447d352007-04-17 23:44:08 +09002668 rc = mv_init_host(host, board_idx);
Tejun Heo24dc5f32007-01-20 16:00:28 +09002669 if (rc)
2670 return rc;
Brett Russ20f733e72005-09-01 18:26:17 -04002671
Brett Russ31961942005-09-30 01:36:00 -04002672 /* Enable interrupts */
Tejun Heo6a59dcf2007-02-24 15:12:31 +09002673 if (msi && pci_enable_msi(pdev))
Brett Russ31961942005-09-30 01:36:00 -04002674 pci_intx(pdev, 1);
Brett Russ20f733e72005-09-01 18:26:17 -04002675
Brett Russ31961942005-09-30 01:36:00 -04002676 mv_dump_pci_cfg(pdev, 0x68);
Tejun Heo4447d352007-04-17 23:44:08 +09002677 mv_print_info(host);
Brett Russ20f733e72005-09-01 18:26:17 -04002678
Tejun Heo4447d352007-04-17 23:44:08 +09002679 pci_set_master(pdev);
Jeff Garzikea8b4db2007-07-17 02:21:50 -04002680 pci_try_set_mwi(pdev);
Tejun Heo4447d352007-04-17 23:44:08 +09002681 return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
Jeff Garzikc5d3e452007-07-11 18:30:50 -04002682 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
Brett Russ20f733e72005-09-01 18:26:17 -04002683}
2684
2685static int __init mv_init(void)
2686{
Pavel Roskinb7887192006-08-10 18:13:18 +09002687 return pci_register_driver(&mv_pci_driver);
Brett Russ20f733e72005-09-01 18:26:17 -04002688}
2689
2690static void __exit mv_exit(void)
2691{
2692 pci_unregister_driver(&mv_pci_driver);
2693}
2694
2695MODULE_AUTHOR("Brett Russ");
2696MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
2697MODULE_LICENSE("GPL");
2698MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
2699MODULE_VERSION(DRV_VERSION);
2700
Jeff Garzikddef9bb2006-02-02 16:17:06 -05002701module_param(msi, int, 0444);
2702MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
2703
Brett Russ20f733e72005-09-01 18:26:17 -04002704module_init(mv_init);
2705module_exit(mv_exit);