1c6fd2807SJeff Garzik /* 2c6fd2807SJeff Garzik * sata_mv.c - Marvell SATA support 3c6fd2807SJeff Garzik * 4c6fd2807SJeff Garzik * Copyright 2005: EMC Corporation, all rights reserved. 5c6fd2807SJeff Garzik * Copyright 2005 Red Hat, Inc. All rights reserved. 6c6fd2807SJeff Garzik * 7c6fd2807SJeff Garzik * Please ALWAYS copy linux-ide@vger.kernel.org on emails. 8c6fd2807SJeff Garzik * 9c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 10c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 11c6fd2807SJeff Garzik * the Free Software Foundation; version 2 of the License. 12c6fd2807SJeff Garzik * 13c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 14c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c6fd2807SJeff Garzik * GNU General Public License for more details. 17c6fd2807SJeff Garzik * 18c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 19c6fd2807SJeff Garzik * along with this program; if not, write to the Free Software 20c6fd2807SJeff Garzik * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21c6fd2807SJeff Garzik * 22c6fd2807SJeff Garzik */ 23c6fd2807SJeff Garzik 244a05e209SJeff Garzik /* 254a05e209SJeff Garzik sata_mv TODO list: 264a05e209SJeff Garzik 274a05e209SJeff Garzik 1) Needs a full errata audit for all chipsets. I implemented most 284a05e209SJeff Garzik of the errata workarounds found in the Marvell vendor driver, but 294a05e209SJeff Garzik I distinctly remember a couple workarounds (one related to PCI-X) 304a05e209SJeff Garzik are still needed. 314a05e209SJeff Garzik 324a05e209SJeff Garzik 2) Convert to LibATA new EH. Required for hotplug, NCQ, and sane 334a05e209SJeff Garzik probing/error handling in general. MUST HAVE. 344a05e209SJeff Garzik 354a05e209SJeff Garzik 3) Add hotplug support (easy, once new-EH support appears) 364a05e209SJeff Garzik 374a05e209SJeff Garzik 4) Add NCQ support (easy to intermediate, once new-EH support appears) 384a05e209SJeff Garzik 394a05e209SJeff Garzik 5) Investigate problems with PCI Message Signalled Interrupts (MSI). 404a05e209SJeff Garzik 414a05e209SJeff Garzik 6) Add port multiplier support (intermediate) 424a05e209SJeff Garzik 434a05e209SJeff Garzik 7) Test and verify 3.0 Gbps support 444a05e209SJeff Garzik 454a05e209SJeff Garzik 8) Develop a low-power-consumption strategy, and implement it. 464a05e209SJeff Garzik 474a05e209SJeff Garzik 9) [Experiment, low priority] See if ATAPI can be supported using 484a05e209SJeff Garzik "unknown FIS" or "vendor-specific FIS" support, or something creative 494a05e209SJeff Garzik like that. 504a05e209SJeff Garzik 514a05e209SJeff Garzik 10) [Experiment, low priority] Investigate interrupt coalescing. 524a05e209SJeff Garzik Quite often, especially with PCI Message Signalled Interrupts (MSI), 534a05e209SJeff Garzik the overhead reduced by interrupt mitigation is quite often not 544a05e209SJeff Garzik worth the latency cost. 554a05e209SJeff Garzik 564a05e209SJeff Garzik 11) [Experiment, Marvell value added] Is it possible to use target 574a05e209SJeff Garzik mode to cross-connect two Linux boxes with Marvell cards? If so, 584a05e209SJeff Garzik creating LibATA target mode support would be very interesting. 594a05e209SJeff Garzik 604a05e209SJeff Garzik Target mode, for those without docs, is the ability to directly 614a05e209SJeff Garzik connect two SATA controllers. 624a05e209SJeff Garzik 634a05e209SJeff Garzik 13) Verify that 7042 is fully supported. I only have a 6042. 644a05e209SJeff Garzik 654a05e209SJeff Garzik */ 664a05e209SJeff Garzik 674a05e209SJeff Garzik 68c6fd2807SJeff Garzik #include <linux/kernel.h> 69c6fd2807SJeff Garzik #include <linux/module.h> 70c6fd2807SJeff Garzik #include <linux/pci.h> 71c6fd2807SJeff Garzik #include <linux/init.h> 72c6fd2807SJeff Garzik #include <linux/blkdev.h> 73c6fd2807SJeff Garzik #include <linux/delay.h> 74c6fd2807SJeff Garzik #include <linux/interrupt.h> 75c6fd2807SJeff Garzik #include <linux/dma-mapping.h> 76c6fd2807SJeff Garzik #include <linux/device.h> 77c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 78c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h> 79c6fd2807SJeff Garzik #include <linux/libata.h> 80c6fd2807SJeff Garzik 81c6fd2807SJeff Garzik #define DRV_NAME "sata_mv" 828bc3fc47SJeff Garzik #define DRV_VERSION "0.81" 83c6fd2807SJeff Garzik 84c6fd2807SJeff Garzik enum { 85c6fd2807SJeff Garzik /* BAR's are enumerated in terms of pci_resource_start() terms */ 86c6fd2807SJeff Garzik MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */ 87c6fd2807SJeff Garzik MV_IO_BAR = 2, /* offset 0x18: IO space */ 88c6fd2807SJeff Garzik MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */ 89c6fd2807SJeff Garzik 90c6fd2807SJeff Garzik MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */ 91c6fd2807SJeff Garzik MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */ 92c6fd2807SJeff Garzik 93c6fd2807SJeff Garzik MV_PCI_REG_BASE = 0, 94c6fd2807SJeff Garzik MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */ 95c6fd2807SJeff Garzik MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08), 96c6fd2807SJeff Garzik MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88), 97c6fd2807SJeff Garzik MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c), 98c6fd2807SJeff Garzik MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc), 99c6fd2807SJeff Garzik MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0), 100c6fd2807SJeff Garzik 101c6fd2807SJeff Garzik MV_SATAHC0_REG_BASE = 0x20000, 102c6fd2807SJeff Garzik MV_FLASH_CTL = 0x1046c, 103c6fd2807SJeff Garzik MV_GPIO_PORT_CTL = 0x104f0, 104c6fd2807SJeff Garzik MV_RESET_CFG = 0x180d8, 105c6fd2807SJeff Garzik 106c6fd2807SJeff Garzik MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ, 107c6fd2807SJeff Garzik MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ, 108c6fd2807SJeff Garzik MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */ 109c6fd2807SJeff Garzik MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ, 110c6fd2807SJeff Garzik 111c6fd2807SJeff Garzik MV_USE_Q_DEPTH = ATA_DEF_QUEUE, 112c6fd2807SJeff Garzik 113c6fd2807SJeff Garzik MV_MAX_Q_DEPTH = 32, 114c6fd2807SJeff Garzik MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1, 115c6fd2807SJeff Garzik 116c6fd2807SJeff Garzik /* CRQB needs alignment on a 1KB boundary. Size == 1KB 117c6fd2807SJeff Garzik * CRPB needs alignment on a 256B boundary. Size == 256B 118c6fd2807SJeff Garzik * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB 119c6fd2807SJeff Garzik * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B 120c6fd2807SJeff Garzik */ 121c6fd2807SJeff Garzik MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH), 122c6fd2807SJeff Garzik MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH), 123c6fd2807SJeff Garzik MV_MAX_SG_CT = 176, 124c6fd2807SJeff Garzik MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT), 125c6fd2807SJeff Garzik MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ), 126c6fd2807SJeff Garzik 127c6fd2807SJeff Garzik MV_PORTS_PER_HC = 4, 128c6fd2807SJeff Garzik /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */ 129c6fd2807SJeff Garzik MV_PORT_HC_SHIFT = 2, 130c6fd2807SJeff Garzik /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */ 131c6fd2807SJeff Garzik MV_PORT_MASK = 3, 132c6fd2807SJeff Garzik 133c6fd2807SJeff Garzik /* Host Flags */ 134c6fd2807SJeff Garzik MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */ 135c6fd2807SJeff Garzik MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */ 136c6fd2807SJeff Garzik MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 137c6fd2807SJeff Garzik ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | 138c6fd2807SJeff Garzik ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING), 139c6fd2807SJeff Garzik MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE, 140c6fd2807SJeff Garzik 141c6fd2807SJeff Garzik CRQB_FLAG_READ = (1 << 0), 142c6fd2807SJeff Garzik CRQB_TAG_SHIFT = 1, 143c6fd2807SJeff Garzik CRQB_CMD_ADDR_SHIFT = 8, 144c6fd2807SJeff Garzik CRQB_CMD_CS = (0x2 << 11), 145c6fd2807SJeff Garzik CRQB_CMD_LAST = (1 << 15), 146c6fd2807SJeff Garzik 147c6fd2807SJeff Garzik CRPB_FLAG_STATUS_SHIFT = 8, 148c6fd2807SJeff Garzik 149c6fd2807SJeff Garzik EPRD_FLAG_END_OF_TBL = (1 << 31), 150c6fd2807SJeff Garzik 151c6fd2807SJeff Garzik /* PCI interface registers */ 152c6fd2807SJeff Garzik 153c6fd2807SJeff Garzik PCI_COMMAND_OFS = 0xc00, 154c6fd2807SJeff Garzik 155c6fd2807SJeff Garzik PCI_MAIN_CMD_STS_OFS = 0xd30, 156c6fd2807SJeff Garzik STOP_PCI_MASTER = (1 << 2), 157c6fd2807SJeff Garzik PCI_MASTER_EMPTY = (1 << 3), 158c6fd2807SJeff Garzik GLOB_SFT_RST = (1 << 4), 159c6fd2807SJeff Garzik 160c6fd2807SJeff Garzik MV_PCI_MODE = 0xd00, 161c6fd2807SJeff Garzik MV_PCI_EXP_ROM_BAR_CTL = 0xd2c, 162c6fd2807SJeff Garzik MV_PCI_DISC_TIMER = 0xd04, 163c6fd2807SJeff Garzik MV_PCI_MSI_TRIGGER = 0xc38, 164c6fd2807SJeff Garzik MV_PCI_SERR_MASK = 0xc28, 165c6fd2807SJeff Garzik MV_PCI_XBAR_TMOUT = 0x1d04, 166c6fd2807SJeff Garzik MV_PCI_ERR_LOW_ADDRESS = 0x1d40, 167c6fd2807SJeff Garzik MV_PCI_ERR_HIGH_ADDRESS = 0x1d44, 168c6fd2807SJeff Garzik MV_PCI_ERR_ATTRIBUTE = 0x1d48, 169c6fd2807SJeff Garzik MV_PCI_ERR_COMMAND = 0x1d50, 170c6fd2807SJeff Garzik 171c6fd2807SJeff Garzik PCI_IRQ_CAUSE_OFS = 0x1d58, 172c6fd2807SJeff Garzik PCI_IRQ_MASK_OFS = 0x1d5c, 173c6fd2807SJeff Garzik PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */ 174c6fd2807SJeff Garzik 175c6fd2807SJeff Garzik HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, 176c6fd2807SJeff Garzik HC_MAIN_IRQ_MASK_OFS = 0x1d64, 177c6fd2807SJeff Garzik PORT0_ERR = (1 << 0), /* shift by port # */ 178c6fd2807SJeff Garzik PORT0_DONE = (1 << 1), /* shift by port # */ 179c6fd2807SJeff Garzik HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */ 180c6fd2807SJeff Garzik HC_SHIFT = 9, /* bits 9-17 = HC1's ports */ 181c6fd2807SJeff Garzik PCI_ERR = (1 << 18), 182c6fd2807SJeff Garzik TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */ 183c6fd2807SJeff Garzik TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */ 184fb621e2fSJeff Garzik PORTS_0_3_COAL_DONE = (1 << 8), 185fb621e2fSJeff Garzik PORTS_4_7_COAL_DONE = (1 << 17), 186c6fd2807SJeff Garzik PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */ 187c6fd2807SJeff Garzik GPIO_INT = (1 << 22), 188c6fd2807SJeff Garzik SELF_INT = (1 << 23), 189c6fd2807SJeff Garzik TWSI_INT = (1 << 24), 190c6fd2807SJeff Garzik HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */ 191fb621e2fSJeff Garzik HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */ 192c6fd2807SJeff Garzik HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | 193c6fd2807SJeff Garzik PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT | 194c6fd2807SJeff Garzik HC_MAIN_RSVD), 195fb621e2fSJeff Garzik HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE | 196fb621e2fSJeff Garzik HC_MAIN_RSVD_5), 197c6fd2807SJeff Garzik 198c6fd2807SJeff Garzik /* SATAHC registers */ 199c6fd2807SJeff Garzik HC_CFG_OFS = 0, 200c6fd2807SJeff Garzik 201c6fd2807SJeff Garzik HC_IRQ_CAUSE_OFS = 0x14, 202c6fd2807SJeff Garzik CRPB_DMA_DONE = (1 << 0), /* shift by port # */ 203c6fd2807SJeff Garzik HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */ 204c6fd2807SJeff Garzik DEV_IRQ = (1 << 8), /* shift by port # */ 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik /* Shadow block registers */ 207c6fd2807SJeff Garzik SHD_BLK_OFS = 0x100, 208c6fd2807SJeff Garzik SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */ 209c6fd2807SJeff Garzik 210c6fd2807SJeff Garzik /* SATA registers */ 211c6fd2807SJeff Garzik SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */ 212c6fd2807SJeff Garzik SATA_ACTIVE_OFS = 0x350, 213c6fd2807SJeff Garzik PHY_MODE3 = 0x310, 214c6fd2807SJeff Garzik PHY_MODE4 = 0x314, 215c6fd2807SJeff Garzik PHY_MODE2 = 0x330, 216c6fd2807SJeff Garzik MV5_PHY_MODE = 0x74, 217c6fd2807SJeff Garzik MV5_LT_MODE = 0x30, 218c6fd2807SJeff Garzik MV5_PHY_CTL = 0x0C, 219c6fd2807SJeff Garzik SATA_INTERFACE_CTL = 0x050, 220c6fd2807SJeff Garzik 221c6fd2807SJeff Garzik MV_M2_PREAMP_MASK = 0x7e0, 222c6fd2807SJeff Garzik 223c6fd2807SJeff Garzik /* Port registers */ 224c6fd2807SJeff Garzik EDMA_CFG_OFS = 0, 225c6fd2807SJeff Garzik EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */ 226c6fd2807SJeff Garzik EDMA_CFG_NCQ = (1 << 5), 227c6fd2807SJeff Garzik EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */ 228c6fd2807SJeff Garzik EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */ 229c6fd2807SJeff Garzik EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */ 230c6fd2807SJeff Garzik 231c6fd2807SJeff Garzik EDMA_ERR_IRQ_CAUSE_OFS = 0x8, 232c6fd2807SJeff Garzik EDMA_ERR_IRQ_MASK_OFS = 0xc, 233c6fd2807SJeff Garzik EDMA_ERR_D_PAR = (1 << 0), 234c6fd2807SJeff Garzik EDMA_ERR_PRD_PAR = (1 << 1), 235c6fd2807SJeff Garzik EDMA_ERR_DEV = (1 << 2), 236c6fd2807SJeff Garzik EDMA_ERR_DEV_DCON = (1 << 3), 237c6fd2807SJeff Garzik EDMA_ERR_DEV_CON = (1 << 4), 238c6fd2807SJeff Garzik EDMA_ERR_SERR = (1 << 5), 239c6fd2807SJeff Garzik EDMA_ERR_SELF_DIS = (1 << 7), 240c6fd2807SJeff Garzik EDMA_ERR_BIST_ASYNC = (1 << 8), 241c6fd2807SJeff Garzik EDMA_ERR_CRBQ_PAR = (1 << 9), 242c6fd2807SJeff Garzik EDMA_ERR_CRPB_PAR = (1 << 10), 243c6fd2807SJeff Garzik EDMA_ERR_INTRL_PAR = (1 << 11), 244c6fd2807SJeff Garzik EDMA_ERR_IORDY = (1 << 12), 245c6fd2807SJeff Garzik EDMA_ERR_LNK_CTRL_RX = (0xf << 13), 246c6fd2807SJeff Garzik EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15), 247c6fd2807SJeff Garzik EDMA_ERR_LNK_DATA_RX = (0xf << 17), 248c6fd2807SJeff Garzik EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), 249c6fd2807SJeff Garzik EDMA_ERR_LNK_DATA_TX = (0x1f << 26), 250c6fd2807SJeff Garzik EDMA_ERR_TRANS_PROTO = (1 << 31), 251c6fd2807SJeff Garzik EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR | 252c6fd2807SJeff Garzik EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR | 253c6fd2807SJeff Garzik EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR | 254c6fd2807SJeff Garzik EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 | 255c6fd2807SJeff Garzik EDMA_ERR_LNK_DATA_RX | 256c6fd2807SJeff Garzik EDMA_ERR_LNK_DATA_TX | 257c6fd2807SJeff Garzik EDMA_ERR_TRANS_PROTO), 258c6fd2807SJeff Garzik 259c6fd2807SJeff Garzik EDMA_REQ_Q_BASE_HI_OFS = 0x10, 260c6fd2807SJeff Garzik EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */ 261c6fd2807SJeff Garzik 262c6fd2807SJeff Garzik EDMA_REQ_Q_OUT_PTR_OFS = 0x18, 263c6fd2807SJeff Garzik EDMA_REQ_Q_PTR_SHIFT = 5, 264c6fd2807SJeff Garzik 265c6fd2807SJeff Garzik EDMA_RSP_Q_BASE_HI_OFS = 0x1c, 266c6fd2807SJeff Garzik EDMA_RSP_Q_IN_PTR_OFS = 0x20, 267c6fd2807SJeff Garzik EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */ 268c6fd2807SJeff Garzik EDMA_RSP_Q_PTR_SHIFT = 3, 269c6fd2807SJeff Garzik 270c6fd2807SJeff Garzik EDMA_CMD_OFS = 0x28, 271c6fd2807SJeff Garzik EDMA_EN = (1 << 0), 272c6fd2807SJeff Garzik EDMA_DS = (1 << 1), 273c6fd2807SJeff Garzik ATA_RST = (1 << 2), 274c6fd2807SJeff Garzik 275c6fd2807SJeff Garzik EDMA_IORDY_TMOUT = 0x34, 276c6fd2807SJeff Garzik EDMA_ARB_CFG = 0x38, 277c6fd2807SJeff Garzik 278c6fd2807SJeff Garzik /* Host private flags (hp_flags) */ 279c6fd2807SJeff Garzik MV_HP_FLAG_MSI = (1 << 0), 280c6fd2807SJeff Garzik MV_HP_ERRATA_50XXB0 = (1 << 1), 281c6fd2807SJeff Garzik MV_HP_ERRATA_50XXB2 = (1 << 2), 282c6fd2807SJeff Garzik MV_HP_ERRATA_60X1B2 = (1 << 3), 283c6fd2807SJeff Garzik MV_HP_ERRATA_60X1C0 = (1 << 4), 284c6fd2807SJeff Garzik MV_HP_ERRATA_XX42A0 = (1 << 5), 285c6fd2807SJeff Garzik MV_HP_50XX = (1 << 6), 286c6fd2807SJeff Garzik MV_HP_GEN_IIE = (1 << 7), 287c6fd2807SJeff Garzik 288c6fd2807SJeff Garzik /* Port private flags (pp_flags) */ 289c6fd2807SJeff Garzik MV_PP_FLAG_EDMA_EN = (1 << 0), 290c6fd2807SJeff Garzik MV_PP_FLAG_EDMA_DS_ACT = (1 << 1), 291c6fd2807SJeff Garzik }; 292c6fd2807SJeff Garzik 293c6fd2807SJeff Garzik #define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX) 294c6fd2807SJeff Garzik #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0) 295c6fd2807SJeff Garzik #define IS_GEN_I(hpriv) IS_50XX(hpriv) 296c6fd2807SJeff Garzik #define IS_GEN_II(hpriv) IS_60XX(hpriv) 297c6fd2807SJeff Garzik #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) 298c6fd2807SJeff Garzik 299c6fd2807SJeff Garzik enum { 300d88184fbSJeff Garzik MV_DMA_BOUNDARY = 0xffffffffU, 301c6fd2807SJeff Garzik 302c6fd2807SJeff Garzik EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U, 303c6fd2807SJeff Garzik 304c6fd2807SJeff Garzik EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U, 305c6fd2807SJeff Garzik }; 306c6fd2807SJeff Garzik 307c6fd2807SJeff Garzik enum chip_type { 308c6fd2807SJeff Garzik chip_504x, 309c6fd2807SJeff Garzik chip_508x, 310c6fd2807SJeff Garzik chip_5080, 311c6fd2807SJeff Garzik chip_604x, 312c6fd2807SJeff Garzik chip_608x, 313c6fd2807SJeff Garzik chip_6042, 314c6fd2807SJeff Garzik chip_7042, 315c6fd2807SJeff Garzik }; 316c6fd2807SJeff Garzik 317c6fd2807SJeff Garzik /* Command ReQuest Block: 32B */ 318c6fd2807SJeff Garzik struct mv_crqb { 319c6fd2807SJeff Garzik __le32 sg_addr; 320c6fd2807SJeff Garzik __le32 sg_addr_hi; 321c6fd2807SJeff Garzik __le16 ctrl_flags; 322c6fd2807SJeff Garzik __le16 ata_cmd[11]; 323c6fd2807SJeff Garzik }; 324c6fd2807SJeff Garzik 325c6fd2807SJeff Garzik struct mv_crqb_iie { 326c6fd2807SJeff Garzik __le32 addr; 327c6fd2807SJeff Garzik __le32 addr_hi; 328c6fd2807SJeff Garzik __le32 flags; 329c6fd2807SJeff Garzik __le32 len; 330c6fd2807SJeff Garzik __le32 ata_cmd[4]; 331c6fd2807SJeff Garzik }; 332c6fd2807SJeff Garzik 333c6fd2807SJeff Garzik /* Command ResPonse Block: 8B */ 334c6fd2807SJeff Garzik struct mv_crpb { 335c6fd2807SJeff Garzik __le16 id; 336c6fd2807SJeff Garzik __le16 flags; 337c6fd2807SJeff Garzik __le32 tmstmp; 338c6fd2807SJeff Garzik }; 339c6fd2807SJeff Garzik 340c6fd2807SJeff Garzik /* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */ 341c6fd2807SJeff Garzik struct mv_sg { 342c6fd2807SJeff Garzik __le32 addr; 343c6fd2807SJeff Garzik __le32 flags_size; 344c6fd2807SJeff Garzik __le32 addr_hi; 345c6fd2807SJeff Garzik __le32 reserved; 346c6fd2807SJeff Garzik }; 347c6fd2807SJeff Garzik 348c6fd2807SJeff Garzik struct mv_port_priv { 349c6fd2807SJeff Garzik struct mv_crqb *crqb; 350c6fd2807SJeff Garzik dma_addr_t crqb_dma; 351c6fd2807SJeff Garzik struct mv_crpb *crpb; 352c6fd2807SJeff Garzik dma_addr_t crpb_dma; 353c6fd2807SJeff Garzik struct mv_sg *sg_tbl; 354c6fd2807SJeff Garzik dma_addr_t sg_tbl_dma; 355c6fd2807SJeff Garzik u32 pp_flags; 356c6fd2807SJeff Garzik }; 357c6fd2807SJeff Garzik 358c6fd2807SJeff Garzik struct mv_port_signal { 359c6fd2807SJeff Garzik u32 amps; 360c6fd2807SJeff Garzik u32 pre; 361c6fd2807SJeff Garzik }; 362c6fd2807SJeff Garzik 363c6fd2807SJeff Garzik struct mv_host_priv; 364c6fd2807SJeff Garzik struct mv_hw_ops { 365c6fd2807SJeff Garzik void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio, 366c6fd2807SJeff Garzik unsigned int port); 367c6fd2807SJeff Garzik void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio); 368c6fd2807SJeff Garzik void (*read_preamp)(struct mv_host_priv *hpriv, int idx, 369c6fd2807SJeff Garzik void __iomem *mmio); 370c6fd2807SJeff Garzik int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio, 371c6fd2807SJeff Garzik unsigned int n_hc); 372c6fd2807SJeff Garzik void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio); 373c6fd2807SJeff Garzik void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); 374c6fd2807SJeff Garzik }; 375c6fd2807SJeff Garzik 376c6fd2807SJeff Garzik struct mv_host_priv { 377c6fd2807SJeff Garzik u32 hp_flags; 378c6fd2807SJeff Garzik struct mv_port_signal signal[8]; 379c6fd2807SJeff Garzik const struct mv_hw_ops *ops; 380c6fd2807SJeff Garzik }; 381c6fd2807SJeff Garzik 382c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap); 383c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); 384c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); 385c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in); 386c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); 387c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap); 388c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep); 389c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap); 390c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap); 391c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc); 392c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc); 393c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); 394c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap); 395c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 396c6fd2807SJeff Garzik 397c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, 398c6fd2807SJeff Garzik unsigned int port); 399c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); 400c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, 401c6fd2807SJeff Garzik void __iomem *mmio); 402c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, 403c6fd2807SJeff Garzik unsigned int n_hc); 404c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); 405c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio); 406c6fd2807SJeff Garzik 407c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, 408c6fd2807SJeff Garzik unsigned int port); 409c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); 410c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, 411c6fd2807SJeff Garzik void __iomem *mmio); 412c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, 413c6fd2807SJeff Garzik unsigned int n_hc); 414c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); 415c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio); 416c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, 417c6fd2807SJeff Garzik unsigned int port_no); 418c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap); 419c6fd2807SJeff Garzik 420c6fd2807SJeff Garzik static struct scsi_host_template mv_sht = { 421c6fd2807SJeff Garzik .module = THIS_MODULE, 422c6fd2807SJeff Garzik .name = DRV_NAME, 423c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 424c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 425c6fd2807SJeff Garzik .can_queue = MV_USE_Q_DEPTH, 426c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 427d88184fbSJeff Garzik .sg_tablesize = MV_MAX_SG_CT, 428c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 429c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 430d88184fbSJeff Garzik .use_clustering = 1, 431c6fd2807SJeff Garzik .proc_name = DRV_NAME, 432c6fd2807SJeff Garzik .dma_boundary = MV_DMA_BOUNDARY, 433c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 434c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 435c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 436c6fd2807SJeff Garzik }; 437c6fd2807SJeff Garzik 438c6fd2807SJeff Garzik static const struct ata_port_operations mv5_ops = { 439c6fd2807SJeff Garzik .port_disable = ata_port_disable, 440c6fd2807SJeff Garzik 441c6fd2807SJeff Garzik .tf_load = ata_tf_load, 442c6fd2807SJeff Garzik .tf_read = ata_tf_read, 443c6fd2807SJeff Garzik .check_status = ata_check_status, 444c6fd2807SJeff Garzik .exec_command = ata_exec_command, 445c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 446c6fd2807SJeff Garzik 447c6fd2807SJeff Garzik .phy_reset = mv_phy_reset, 448cffacd85SJeff Garzik .cable_detect = ata_cable_sata, 449c6fd2807SJeff Garzik 450c6fd2807SJeff Garzik .qc_prep = mv_qc_prep, 451c6fd2807SJeff Garzik .qc_issue = mv_qc_issue, 4520d5ff566STejun Heo .data_xfer = ata_data_xfer, 453c6fd2807SJeff Garzik 454c6fd2807SJeff Garzik .eng_timeout = mv_eng_timeout, 455c6fd2807SJeff Garzik 456c6fd2807SJeff Garzik .irq_clear = mv_irq_clear, 457246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 458246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 459c6fd2807SJeff Garzik 460c6fd2807SJeff Garzik .scr_read = mv5_scr_read, 461c6fd2807SJeff Garzik .scr_write = mv5_scr_write, 462c6fd2807SJeff Garzik 463c6fd2807SJeff Garzik .port_start = mv_port_start, 464c6fd2807SJeff Garzik .port_stop = mv_port_stop, 465c6fd2807SJeff Garzik }; 466c6fd2807SJeff Garzik 467c6fd2807SJeff Garzik static const struct ata_port_operations mv6_ops = { 468c6fd2807SJeff Garzik .port_disable = ata_port_disable, 469c6fd2807SJeff Garzik 470c6fd2807SJeff Garzik .tf_load = ata_tf_load, 471c6fd2807SJeff Garzik .tf_read = ata_tf_read, 472c6fd2807SJeff Garzik .check_status = ata_check_status, 473c6fd2807SJeff Garzik .exec_command = ata_exec_command, 474c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 475c6fd2807SJeff Garzik 476c6fd2807SJeff Garzik .phy_reset = mv_phy_reset, 477cffacd85SJeff Garzik .cable_detect = ata_cable_sata, 478c6fd2807SJeff Garzik 479c6fd2807SJeff Garzik .qc_prep = mv_qc_prep, 480c6fd2807SJeff Garzik .qc_issue = mv_qc_issue, 4810d5ff566STejun Heo .data_xfer = ata_data_xfer, 482c6fd2807SJeff Garzik 483c6fd2807SJeff Garzik .eng_timeout = mv_eng_timeout, 484c6fd2807SJeff Garzik 485c6fd2807SJeff Garzik .irq_clear = mv_irq_clear, 486246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 487246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 488c6fd2807SJeff Garzik 489c6fd2807SJeff Garzik .scr_read = mv_scr_read, 490c6fd2807SJeff Garzik .scr_write = mv_scr_write, 491c6fd2807SJeff Garzik 492c6fd2807SJeff Garzik .port_start = mv_port_start, 493c6fd2807SJeff Garzik .port_stop = mv_port_stop, 494c6fd2807SJeff Garzik }; 495c6fd2807SJeff Garzik 496c6fd2807SJeff Garzik static const struct ata_port_operations mv_iie_ops = { 497c6fd2807SJeff Garzik .port_disable = ata_port_disable, 498c6fd2807SJeff Garzik 499c6fd2807SJeff Garzik .tf_load = ata_tf_load, 500c6fd2807SJeff Garzik .tf_read = ata_tf_read, 501c6fd2807SJeff Garzik .check_status = ata_check_status, 502c6fd2807SJeff Garzik .exec_command = ata_exec_command, 503c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 504c6fd2807SJeff Garzik 505c6fd2807SJeff Garzik .phy_reset = mv_phy_reset, 506cffacd85SJeff Garzik .cable_detect = ata_cable_sata, 507c6fd2807SJeff Garzik 508c6fd2807SJeff Garzik .qc_prep = mv_qc_prep_iie, 509c6fd2807SJeff Garzik .qc_issue = mv_qc_issue, 5100d5ff566STejun Heo .data_xfer = ata_data_xfer, 511c6fd2807SJeff Garzik 512c6fd2807SJeff Garzik .eng_timeout = mv_eng_timeout, 513c6fd2807SJeff Garzik 514c6fd2807SJeff Garzik .irq_clear = mv_irq_clear, 515246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 516246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 517c6fd2807SJeff Garzik 518c6fd2807SJeff Garzik .scr_read = mv_scr_read, 519c6fd2807SJeff Garzik .scr_write = mv_scr_write, 520c6fd2807SJeff Garzik 521c6fd2807SJeff Garzik .port_start = mv_port_start, 522c6fd2807SJeff Garzik .port_stop = mv_port_stop, 523c6fd2807SJeff Garzik }; 524c6fd2807SJeff Garzik 525c6fd2807SJeff Garzik static const struct ata_port_info mv_port_info[] = { 526c6fd2807SJeff Garzik { /* chip_504x */ 527cca3974eSJeff Garzik .flags = MV_COMMON_FLAGS, 528c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 529bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 530c6fd2807SJeff Garzik .port_ops = &mv5_ops, 531c6fd2807SJeff Garzik }, 532c6fd2807SJeff Garzik { /* chip_508x */ 533cca3974eSJeff Garzik .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), 534c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 535bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 536c6fd2807SJeff Garzik .port_ops = &mv5_ops, 537c6fd2807SJeff Garzik }, 538c6fd2807SJeff Garzik { /* chip_5080 */ 539cca3974eSJeff Garzik .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC), 540c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 541bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 542c6fd2807SJeff Garzik .port_ops = &mv5_ops, 543c6fd2807SJeff Garzik }, 544c6fd2807SJeff Garzik { /* chip_604x */ 545cca3974eSJeff Garzik .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), 546c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 547bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 548c6fd2807SJeff Garzik .port_ops = &mv6_ops, 549c6fd2807SJeff Garzik }, 550c6fd2807SJeff Garzik { /* chip_608x */ 551cca3974eSJeff Garzik .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS | 552c6fd2807SJeff Garzik MV_FLAG_DUAL_HC), 553c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 554bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 555c6fd2807SJeff Garzik .port_ops = &mv6_ops, 556c6fd2807SJeff Garzik }, 557c6fd2807SJeff Garzik { /* chip_6042 */ 558cca3974eSJeff Garzik .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), 559c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 560bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 561c6fd2807SJeff Garzik .port_ops = &mv_iie_ops, 562c6fd2807SJeff Garzik }, 563c6fd2807SJeff Garzik { /* chip_7042 */ 564e93f09dcSOlof Johansson .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS), 565c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 566bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 567c6fd2807SJeff Garzik .port_ops = &mv_iie_ops, 568c6fd2807SJeff Garzik }, 569c6fd2807SJeff Garzik }; 570c6fd2807SJeff Garzik 571c6fd2807SJeff Garzik static const struct pci_device_id mv_pci_tbl[] = { 5722d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, 5732d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, 5742d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, 5752d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, 576c6fd2807SJeff Garzik 5772d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, 5782d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, 5792d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, 5802d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, 5812d2744fcSJeff Garzik { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, 582c6fd2807SJeff Garzik 5832d2744fcSJeff Garzik { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, 5842d2744fcSJeff Garzik 585d9f9c6bcSFlorian Attenberger /* Adaptec 1430SA */ 586d9f9c6bcSFlorian Attenberger { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, 587d9f9c6bcSFlorian Attenberger 588e93f09dcSOlof Johansson { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, 589e93f09dcSOlof Johansson 5906a3d586dSMorrison, Tom /* add Marvell 7042 support */ 5916a3d586dSMorrison, Tom { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, 5926a3d586dSMorrison, Tom 593c6fd2807SJeff Garzik { } /* terminate list */ 594c6fd2807SJeff Garzik }; 595c6fd2807SJeff Garzik 596c6fd2807SJeff Garzik static struct pci_driver mv_pci_driver = { 597c6fd2807SJeff Garzik .name = DRV_NAME, 598c6fd2807SJeff Garzik .id_table = mv_pci_tbl, 599c6fd2807SJeff Garzik .probe = mv_init_one, 600c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 601c6fd2807SJeff Garzik }; 602c6fd2807SJeff Garzik 603c6fd2807SJeff Garzik static const struct mv_hw_ops mv5xxx_ops = { 604c6fd2807SJeff Garzik .phy_errata = mv5_phy_errata, 605c6fd2807SJeff Garzik .enable_leds = mv5_enable_leds, 606c6fd2807SJeff Garzik .read_preamp = mv5_read_preamp, 607c6fd2807SJeff Garzik .reset_hc = mv5_reset_hc, 608c6fd2807SJeff Garzik .reset_flash = mv5_reset_flash, 609c6fd2807SJeff Garzik .reset_bus = mv5_reset_bus, 610c6fd2807SJeff Garzik }; 611c6fd2807SJeff Garzik 612c6fd2807SJeff Garzik static const struct mv_hw_ops mv6xxx_ops = { 613c6fd2807SJeff Garzik .phy_errata = mv6_phy_errata, 614c6fd2807SJeff Garzik .enable_leds = mv6_enable_leds, 615c6fd2807SJeff Garzik .read_preamp = mv6_read_preamp, 616c6fd2807SJeff Garzik .reset_hc = mv6_reset_hc, 617c6fd2807SJeff Garzik .reset_flash = mv6_reset_flash, 618c6fd2807SJeff Garzik .reset_bus = mv_reset_pci_bus, 619c6fd2807SJeff Garzik }; 620c6fd2807SJeff Garzik 621c6fd2807SJeff Garzik /* 622c6fd2807SJeff Garzik * module options 623c6fd2807SJeff Garzik */ 624c6fd2807SJeff Garzik static int msi; /* Use PCI msi; either zero (off, default) or non-zero */ 625c6fd2807SJeff Garzik 626c6fd2807SJeff Garzik 627d88184fbSJeff Garzik /* move to PCI layer or libata core? */ 628d88184fbSJeff Garzik static int pci_go_64(struct pci_dev *pdev) 629d88184fbSJeff Garzik { 630d88184fbSJeff Garzik int rc; 631d88184fbSJeff Garzik 632d88184fbSJeff Garzik if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 633d88184fbSJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 634d88184fbSJeff Garzik if (rc) { 635d88184fbSJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 636d88184fbSJeff Garzik if (rc) { 637d88184fbSJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 638d88184fbSJeff Garzik "64-bit DMA enable failed\n"); 639d88184fbSJeff Garzik return rc; 640d88184fbSJeff Garzik } 641d88184fbSJeff Garzik } 642d88184fbSJeff Garzik } else { 643d88184fbSJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 644d88184fbSJeff Garzik if (rc) { 645d88184fbSJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 646d88184fbSJeff Garzik "32-bit DMA enable failed\n"); 647d88184fbSJeff Garzik return rc; 648d88184fbSJeff Garzik } 649d88184fbSJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 650d88184fbSJeff Garzik if (rc) { 651d88184fbSJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 652d88184fbSJeff Garzik "32-bit consistent DMA enable failed\n"); 653d88184fbSJeff Garzik return rc; 654d88184fbSJeff Garzik } 655d88184fbSJeff Garzik } 656d88184fbSJeff Garzik 657d88184fbSJeff Garzik return rc; 658d88184fbSJeff Garzik } 659d88184fbSJeff Garzik 660c6fd2807SJeff Garzik /* 661c6fd2807SJeff Garzik * Functions 662c6fd2807SJeff Garzik */ 663c6fd2807SJeff Garzik 664c6fd2807SJeff Garzik static inline void writelfl(unsigned long data, void __iomem *addr) 665c6fd2807SJeff Garzik { 666c6fd2807SJeff Garzik writel(data, addr); 667c6fd2807SJeff Garzik (void) readl(addr); /* flush to avoid PCI posted write */ 668c6fd2807SJeff Garzik } 669c6fd2807SJeff Garzik 670c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc) 671c6fd2807SJeff Garzik { 672c6fd2807SJeff Garzik return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ)); 673c6fd2807SJeff Garzik } 674c6fd2807SJeff Garzik 675c6fd2807SJeff Garzik static inline unsigned int mv_hc_from_port(unsigned int port) 676c6fd2807SJeff Garzik { 677c6fd2807SJeff Garzik return port >> MV_PORT_HC_SHIFT; 678c6fd2807SJeff Garzik } 679c6fd2807SJeff Garzik 680c6fd2807SJeff Garzik static inline unsigned int mv_hardport_from_port(unsigned int port) 681c6fd2807SJeff Garzik { 682c6fd2807SJeff Garzik return port & MV_PORT_MASK; 683c6fd2807SJeff Garzik } 684c6fd2807SJeff Garzik 685c6fd2807SJeff Garzik static inline void __iomem *mv_hc_base_from_port(void __iomem *base, 686c6fd2807SJeff Garzik unsigned int port) 687c6fd2807SJeff Garzik { 688c6fd2807SJeff Garzik return mv_hc_base(base, mv_hc_from_port(port)); 689c6fd2807SJeff Garzik } 690c6fd2807SJeff Garzik 691c6fd2807SJeff Garzik static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port) 692c6fd2807SJeff Garzik { 693c6fd2807SJeff Garzik return mv_hc_base_from_port(base, port) + 694c6fd2807SJeff Garzik MV_SATAHC_ARBTR_REG_SZ + 695c6fd2807SJeff Garzik (mv_hardport_from_port(port) * MV_PORT_REG_SZ); 696c6fd2807SJeff Garzik } 697c6fd2807SJeff Garzik 698c6fd2807SJeff Garzik static inline void __iomem *mv_ap_base(struct ata_port *ap) 699c6fd2807SJeff Garzik { 7000d5ff566STejun Heo return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no); 701c6fd2807SJeff Garzik } 702c6fd2807SJeff Garzik 703cca3974eSJeff Garzik static inline int mv_get_hc_count(unsigned long port_flags) 704c6fd2807SJeff Garzik { 705cca3974eSJeff Garzik return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1); 706c6fd2807SJeff Garzik } 707c6fd2807SJeff Garzik 708c6fd2807SJeff Garzik static void mv_irq_clear(struct ata_port *ap) 709c6fd2807SJeff Garzik { 710c6fd2807SJeff Garzik } 711c6fd2807SJeff Garzik 712c6fd2807SJeff Garzik /** 713c6fd2807SJeff Garzik * mv_start_dma - Enable eDMA engine 714c6fd2807SJeff Garzik * @base: port base address 715c6fd2807SJeff Garzik * @pp: port private data 716c6fd2807SJeff Garzik * 717c6fd2807SJeff Garzik * Verify the local cache of the eDMA state is accurate with a 718c6fd2807SJeff Garzik * WARN_ON. 719c6fd2807SJeff Garzik * 720c6fd2807SJeff Garzik * LOCKING: 721c6fd2807SJeff Garzik * Inherited from caller. 722c6fd2807SJeff Garzik */ 723c6fd2807SJeff Garzik static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp) 724c6fd2807SJeff Garzik { 725c6fd2807SJeff Garzik if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) { 726c6fd2807SJeff Garzik writelfl(EDMA_EN, base + EDMA_CMD_OFS); 727c6fd2807SJeff Garzik pp->pp_flags |= MV_PP_FLAG_EDMA_EN; 728c6fd2807SJeff Garzik } 729c6fd2807SJeff Garzik WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS))); 730c6fd2807SJeff Garzik } 731c6fd2807SJeff Garzik 732c6fd2807SJeff Garzik /** 733c6fd2807SJeff Garzik * mv_stop_dma - Disable eDMA engine 734c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 735c6fd2807SJeff Garzik * 736c6fd2807SJeff Garzik * Verify the local cache of the eDMA state is accurate with a 737c6fd2807SJeff Garzik * WARN_ON. 738c6fd2807SJeff Garzik * 739c6fd2807SJeff Garzik * LOCKING: 740c6fd2807SJeff Garzik * Inherited from caller. 741c6fd2807SJeff Garzik */ 742c6fd2807SJeff Garzik static void mv_stop_dma(struct ata_port *ap) 743c6fd2807SJeff Garzik { 744c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(ap); 745c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 746c6fd2807SJeff Garzik u32 reg; 747c6fd2807SJeff Garzik int i; 748c6fd2807SJeff Garzik 749c6fd2807SJeff Garzik if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) { 750c6fd2807SJeff Garzik /* Disable EDMA if active. The disable bit auto clears. 751c6fd2807SJeff Garzik */ 752c6fd2807SJeff Garzik writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); 753c6fd2807SJeff Garzik pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; 754c6fd2807SJeff Garzik } else { 755c6fd2807SJeff Garzik WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)); 756c6fd2807SJeff Garzik } 757c6fd2807SJeff Garzik 758c6fd2807SJeff Garzik /* now properly wait for the eDMA to stop */ 759c6fd2807SJeff Garzik for (i = 1000; i > 0; i--) { 760c6fd2807SJeff Garzik reg = readl(port_mmio + EDMA_CMD_OFS); 761c6fd2807SJeff Garzik if (!(EDMA_EN & reg)) { 762c6fd2807SJeff Garzik break; 763c6fd2807SJeff Garzik } 764c6fd2807SJeff Garzik udelay(100); 765c6fd2807SJeff Garzik } 766c6fd2807SJeff Garzik 767c6fd2807SJeff Garzik if (EDMA_EN & reg) { 768c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n"); 769c6fd2807SJeff Garzik /* FIXME: Consider doing a reset here to recover */ 770c6fd2807SJeff Garzik } 771c6fd2807SJeff Garzik } 772c6fd2807SJeff Garzik 773c6fd2807SJeff Garzik #ifdef ATA_DEBUG 774c6fd2807SJeff Garzik static void mv_dump_mem(void __iomem *start, unsigned bytes) 775c6fd2807SJeff Garzik { 776c6fd2807SJeff Garzik int b, w; 777c6fd2807SJeff Garzik for (b = 0; b < bytes; ) { 778c6fd2807SJeff Garzik DPRINTK("%p: ", start + b); 779c6fd2807SJeff Garzik for (w = 0; b < bytes && w < 4; w++) { 780c6fd2807SJeff Garzik printk("%08x ",readl(start + b)); 781c6fd2807SJeff Garzik b += sizeof(u32); 782c6fd2807SJeff Garzik } 783c6fd2807SJeff Garzik printk("\n"); 784c6fd2807SJeff Garzik } 785c6fd2807SJeff Garzik } 786c6fd2807SJeff Garzik #endif 787c6fd2807SJeff Garzik 788c6fd2807SJeff Garzik static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) 789c6fd2807SJeff Garzik { 790c6fd2807SJeff Garzik #ifdef ATA_DEBUG 791c6fd2807SJeff Garzik int b, w; 792c6fd2807SJeff Garzik u32 dw; 793c6fd2807SJeff Garzik for (b = 0; b < bytes; ) { 794c6fd2807SJeff Garzik DPRINTK("%02x: ", b); 795c6fd2807SJeff Garzik for (w = 0; b < bytes && w < 4; w++) { 796c6fd2807SJeff Garzik (void) pci_read_config_dword(pdev,b,&dw); 797c6fd2807SJeff Garzik printk("%08x ",dw); 798c6fd2807SJeff Garzik b += sizeof(u32); 799c6fd2807SJeff Garzik } 800c6fd2807SJeff Garzik printk("\n"); 801c6fd2807SJeff Garzik } 802c6fd2807SJeff Garzik #endif 803c6fd2807SJeff Garzik } 804c6fd2807SJeff Garzik static void mv_dump_all_regs(void __iomem *mmio_base, int port, 805c6fd2807SJeff Garzik struct pci_dev *pdev) 806c6fd2807SJeff Garzik { 807c6fd2807SJeff Garzik #ifdef ATA_DEBUG 808c6fd2807SJeff Garzik void __iomem *hc_base = mv_hc_base(mmio_base, 809c6fd2807SJeff Garzik port >> MV_PORT_HC_SHIFT); 810c6fd2807SJeff Garzik void __iomem *port_base; 811c6fd2807SJeff Garzik int start_port, num_ports, p, start_hc, num_hcs, hc; 812c6fd2807SJeff Garzik 813c6fd2807SJeff Garzik if (0 > port) { 814c6fd2807SJeff Garzik start_hc = start_port = 0; 815c6fd2807SJeff Garzik num_ports = 8; /* shld be benign for 4 port devs */ 816c6fd2807SJeff Garzik num_hcs = 2; 817c6fd2807SJeff Garzik } else { 818c6fd2807SJeff Garzik start_hc = port >> MV_PORT_HC_SHIFT; 819c6fd2807SJeff Garzik start_port = port; 820c6fd2807SJeff Garzik num_ports = num_hcs = 1; 821c6fd2807SJeff Garzik } 822c6fd2807SJeff Garzik DPRINTK("All registers for port(s) %u-%u:\n", start_port, 823c6fd2807SJeff Garzik num_ports > 1 ? num_ports - 1 : start_port); 824c6fd2807SJeff Garzik 825c6fd2807SJeff Garzik if (NULL != pdev) { 826c6fd2807SJeff Garzik DPRINTK("PCI config space regs:\n"); 827c6fd2807SJeff Garzik mv_dump_pci_cfg(pdev, 0x68); 828c6fd2807SJeff Garzik } 829c6fd2807SJeff Garzik DPRINTK("PCI regs:\n"); 830c6fd2807SJeff Garzik mv_dump_mem(mmio_base+0xc00, 0x3c); 831c6fd2807SJeff Garzik mv_dump_mem(mmio_base+0xd00, 0x34); 832c6fd2807SJeff Garzik mv_dump_mem(mmio_base+0xf00, 0x4); 833c6fd2807SJeff Garzik mv_dump_mem(mmio_base+0x1d00, 0x6c); 834c6fd2807SJeff Garzik for (hc = start_hc; hc < start_hc + num_hcs; hc++) { 835c6fd2807SJeff Garzik hc_base = mv_hc_base(mmio_base, hc); 836c6fd2807SJeff Garzik DPRINTK("HC regs (HC %i):\n", hc); 837c6fd2807SJeff Garzik mv_dump_mem(hc_base, 0x1c); 838c6fd2807SJeff Garzik } 839c6fd2807SJeff Garzik for (p = start_port; p < start_port + num_ports; p++) { 840c6fd2807SJeff Garzik port_base = mv_port_base(mmio_base, p); 841c6fd2807SJeff Garzik DPRINTK("EDMA regs (port %i):\n",p); 842c6fd2807SJeff Garzik mv_dump_mem(port_base, 0x54); 843c6fd2807SJeff Garzik DPRINTK("SATA regs (port %i):\n",p); 844c6fd2807SJeff Garzik mv_dump_mem(port_base+0x300, 0x60); 845c6fd2807SJeff Garzik } 846c6fd2807SJeff Garzik #endif 847c6fd2807SJeff Garzik } 848c6fd2807SJeff Garzik 849c6fd2807SJeff Garzik static unsigned int mv_scr_offset(unsigned int sc_reg_in) 850c6fd2807SJeff Garzik { 851c6fd2807SJeff Garzik unsigned int ofs; 852c6fd2807SJeff Garzik 853c6fd2807SJeff Garzik switch (sc_reg_in) { 854c6fd2807SJeff Garzik case SCR_STATUS: 855c6fd2807SJeff Garzik case SCR_CONTROL: 856c6fd2807SJeff Garzik case SCR_ERROR: 857c6fd2807SJeff Garzik ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32)); 858c6fd2807SJeff Garzik break; 859c6fd2807SJeff Garzik case SCR_ACTIVE: 860c6fd2807SJeff Garzik ofs = SATA_ACTIVE_OFS; /* active is not with the others */ 861c6fd2807SJeff Garzik break; 862c6fd2807SJeff Garzik default: 863c6fd2807SJeff Garzik ofs = 0xffffffffU; 864c6fd2807SJeff Garzik break; 865c6fd2807SJeff Garzik } 866c6fd2807SJeff Garzik return ofs; 867c6fd2807SJeff Garzik } 868c6fd2807SJeff Garzik 869c6fd2807SJeff Garzik static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in) 870c6fd2807SJeff Garzik { 871c6fd2807SJeff Garzik unsigned int ofs = mv_scr_offset(sc_reg_in); 872c6fd2807SJeff Garzik 87335177265SJeff Garzik if (0xffffffffU != ofs) 874c6fd2807SJeff Garzik return readl(mv_ap_base(ap) + ofs); 87535177265SJeff Garzik else 876c6fd2807SJeff Garzik return (u32) ofs; 877c6fd2807SJeff Garzik } 878c6fd2807SJeff Garzik 879c6fd2807SJeff Garzik static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) 880c6fd2807SJeff Garzik { 881c6fd2807SJeff Garzik unsigned int ofs = mv_scr_offset(sc_reg_in); 882c6fd2807SJeff Garzik 88335177265SJeff Garzik if (0xffffffffU != ofs) 884c6fd2807SJeff Garzik writelfl(val, mv_ap_base(ap) + ofs); 885c6fd2807SJeff Garzik } 886c6fd2807SJeff Garzik 887c6fd2807SJeff Garzik static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio) 888c6fd2807SJeff Garzik { 889c6fd2807SJeff Garzik u32 cfg = readl(port_mmio + EDMA_CFG_OFS); 890c6fd2807SJeff Garzik 891c6fd2807SJeff Garzik /* set up non-NCQ EDMA configuration */ 892c6fd2807SJeff Garzik cfg &= ~(1 << 9); /* disable equeue */ 893c6fd2807SJeff Garzik 894e728eabeSJeff Garzik if (IS_GEN_I(hpriv)) { 895e728eabeSJeff Garzik cfg &= ~0x1f; /* clear queue depth */ 896c6fd2807SJeff Garzik cfg |= (1 << 8); /* enab config burst size mask */ 897e728eabeSJeff Garzik } 898c6fd2807SJeff Garzik 899e728eabeSJeff Garzik else if (IS_GEN_II(hpriv)) { 900e728eabeSJeff Garzik cfg &= ~0x1f; /* clear queue depth */ 901c6fd2807SJeff Garzik cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN; 902e728eabeSJeff Garzik cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */ 903e728eabeSJeff Garzik } 904c6fd2807SJeff Garzik 905c6fd2807SJeff Garzik else if (IS_GEN_IIE(hpriv)) { 906e728eabeSJeff Garzik cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */ 907e728eabeSJeff Garzik cfg |= (1 << 22); /* enab 4-entry host queue cache */ 908c6fd2807SJeff Garzik cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */ 909c6fd2807SJeff Garzik cfg |= (1 << 18); /* enab early completion */ 910e728eabeSJeff Garzik cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */ 911e728eabeSJeff Garzik cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */ 912e728eabeSJeff Garzik cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */ 913c6fd2807SJeff Garzik } 914c6fd2807SJeff Garzik 915c6fd2807SJeff Garzik writelfl(cfg, port_mmio + EDMA_CFG_OFS); 916c6fd2807SJeff Garzik } 917c6fd2807SJeff Garzik 918c6fd2807SJeff Garzik /** 919c6fd2807SJeff Garzik * mv_port_start - Port specific init/start routine. 920c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 921c6fd2807SJeff Garzik * 922c6fd2807SJeff Garzik * Allocate and point to DMA memory, init port private memory, 923c6fd2807SJeff Garzik * zero indices. 924c6fd2807SJeff Garzik * 925c6fd2807SJeff Garzik * LOCKING: 926c6fd2807SJeff Garzik * Inherited from caller. 927c6fd2807SJeff Garzik */ 928c6fd2807SJeff Garzik static int mv_port_start(struct ata_port *ap) 929c6fd2807SJeff Garzik { 930cca3974eSJeff Garzik struct device *dev = ap->host->dev; 931cca3974eSJeff Garzik struct mv_host_priv *hpriv = ap->host->private_data; 932c6fd2807SJeff Garzik struct mv_port_priv *pp; 933c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(ap); 934c6fd2807SJeff Garzik void *mem; 935c6fd2807SJeff Garzik dma_addr_t mem_dma; 93624dc5f33STejun Heo int rc; 937c6fd2807SJeff Garzik 93824dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 939c6fd2807SJeff Garzik if (!pp) 94024dc5f33STejun Heo return -ENOMEM; 941c6fd2807SJeff Garzik 94224dc5f33STejun Heo mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, 943c6fd2807SJeff Garzik GFP_KERNEL); 944c6fd2807SJeff Garzik if (!mem) 94524dc5f33STejun Heo return -ENOMEM; 946c6fd2807SJeff Garzik memset(mem, 0, MV_PORT_PRIV_DMA_SZ); 947c6fd2807SJeff Garzik 948c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 949c6fd2807SJeff Garzik if (rc) 95024dc5f33STejun Heo return rc; 951c6fd2807SJeff Garzik 952c6fd2807SJeff Garzik /* First item in chunk of DMA memory: 953c6fd2807SJeff Garzik * 32-slot command request table (CRQB), 32 bytes each in size 954c6fd2807SJeff Garzik */ 955c6fd2807SJeff Garzik pp->crqb = mem; 956c6fd2807SJeff Garzik pp->crqb_dma = mem_dma; 957c6fd2807SJeff Garzik mem += MV_CRQB_Q_SZ; 958c6fd2807SJeff Garzik mem_dma += MV_CRQB_Q_SZ; 959c6fd2807SJeff Garzik 960c6fd2807SJeff Garzik /* Second item: 961c6fd2807SJeff Garzik * 32-slot command response table (CRPB), 8 bytes each in size 962c6fd2807SJeff Garzik */ 963c6fd2807SJeff Garzik pp->crpb = mem; 964c6fd2807SJeff Garzik pp->crpb_dma = mem_dma; 965c6fd2807SJeff Garzik mem += MV_CRPB_Q_SZ; 966c6fd2807SJeff Garzik mem_dma += MV_CRPB_Q_SZ; 967c6fd2807SJeff Garzik 968c6fd2807SJeff Garzik /* Third item: 969c6fd2807SJeff Garzik * Table of scatter-gather descriptors (ePRD), 16 bytes each 970c6fd2807SJeff Garzik */ 971c6fd2807SJeff Garzik pp->sg_tbl = mem; 972c6fd2807SJeff Garzik pp->sg_tbl_dma = mem_dma; 973c6fd2807SJeff Garzik 974c6fd2807SJeff Garzik mv_edma_cfg(hpriv, port_mmio); 975c6fd2807SJeff Garzik 976c6fd2807SJeff Garzik writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS); 977c6fd2807SJeff Garzik writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, 978c6fd2807SJeff Garzik port_mmio + EDMA_REQ_Q_IN_PTR_OFS); 979c6fd2807SJeff Garzik 980c6fd2807SJeff Garzik if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0) 981c6fd2807SJeff Garzik writelfl(pp->crqb_dma & 0xffffffff, 982c6fd2807SJeff Garzik port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); 983c6fd2807SJeff Garzik else 984c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS); 985c6fd2807SJeff Garzik 986c6fd2807SJeff Garzik writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS); 987c6fd2807SJeff Garzik 988c6fd2807SJeff Garzik if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0) 989c6fd2807SJeff Garzik writelfl(pp->crpb_dma & 0xffffffff, 990c6fd2807SJeff Garzik port_mmio + EDMA_RSP_Q_IN_PTR_OFS); 991c6fd2807SJeff Garzik else 992c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS); 993c6fd2807SJeff Garzik 994c6fd2807SJeff Garzik writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, 995c6fd2807SJeff Garzik port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); 996c6fd2807SJeff Garzik 997c6fd2807SJeff Garzik /* Don't turn on EDMA here...do it before DMA commands only. Else 998c6fd2807SJeff Garzik * we'll be unable to send non-data, PIO, etc due to restricted access 999c6fd2807SJeff Garzik * to shadow regs. 1000c6fd2807SJeff Garzik */ 1001c6fd2807SJeff Garzik ap->private_data = pp; 1002c6fd2807SJeff Garzik return 0; 1003c6fd2807SJeff Garzik } 1004c6fd2807SJeff Garzik 1005c6fd2807SJeff Garzik /** 1006c6fd2807SJeff Garzik * mv_port_stop - Port specific cleanup/stop routine. 1007c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 1008c6fd2807SJeff Garzik * 1009c6fd2807SJeff Garzik * Stop DMA, cleanup port memory. 1010c6fd2807SJeff Garzik * 1011c6fd2807SJeff Garzik * LOCKING: 1012cca3974eSJeff Garzik * This routine uses the host lock to protect the DMA stop. 1013c6fd2807SJeff Garzik */ 1014c6fd2807SJeff Garzik static void mv_port_stop(struct ata_port *ap) 1015c6fd2807SJeff Garzik { 1016c6fd2807SJeff Garzik unsigned long flags; 1017c6fd2807SJeff Garzik 1018cca3974eSJeff Garzik spin_lock_irqsave(&ap->host->lock, flags); 1019c6fd2807SJeff Garzik mv_stop_dma(ap); 1020cca3974eSJeff Garzik spin_unlock_irqrestore(&ap->host->lock, flags); 1021c6fd2807SJeff Garzik } 1022c6fd2807SJeff Garzik 1023c6fd2807SJeff Garzik /** 1024c6fd2807SJeff Garzik * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries 1025c6fd2807SJeff Garzik * @qc: queued command whose SG list to source from 1026c6fd2807SJeff Garzik * 1027c6fd2807SJeff Garzik * Populate the SG list and mark the last entry. 1028c6fd2807SJeff Garzik * 1029c6fd2807SJeff Garzik * LOCKING: 1030c6fd2807SJeff Garzik * Inherited from caller. 1031c6fd2807SJeff Garzik */ 1032d88184fbSJeff Garzik static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) 1033c6fd2807SJeff Garzik { 1034c6fd2807SJeff Garzik struct mv_port_priv *pp = qc->ap->private_data; 1035d88184fbSJeff Garzik unsigned int n_sg = 0; 1036c6fd2807SJeff Garzik struct scatterlist *sg; 1037d88184fbSJeff Garzik struct mv_sg *mv_sg; 1038c6fd2807SJeff Garzik 1039d88184fbSJeff Garzik mv_sg = pp->sg_tbl; 1040c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 1041d88184fbSJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1042d88184fbSJeff Garzik u32 sg_len = sg_dma_len(sg); 1043c6fd2807SJeff Garzik 1044d88184fbSJeff Garzik mv_sg->addr = cpu_to_le32(addr & 0xffffffff); 1045d88184fbSJeff Garzik mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); 1046d88184fbSJeff Garzik mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff); 1047c6fd2807SJeff Garzik 1048d88184fbSJeff Garzik if (ata_sg_is_last(sg, qc)) 1049d88184fbSJeff Garzik mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); 1050c6fd2807SJeff Garzik 1051d88184fbSJeff Garzik mv_sg++; 1052d88184fbSJeff Garzik n_sg++; 1053c6fd2807SJeff Garzik } 1054d88184fbSJeff Garzik 1055d88184fbSJeff Garzik return n_sg; 1056c6fd2807SJeff Garzik } 1057c6fd2807SJeff Garzik 1058c6fd2807SJeff Garzik static inline unsigned mv_inc_q_index(unsigned index) 1059c6fd2807SJeff Garzik { 1060c6fd2807SJeff Garzik return (index + 1) & MV_MAX_Q_DEPTH_MASK; 1061c6fd2807SJeff Garzik } 1062c6fd2807SJeff Garzik 1063c6fd2807SJeff Garzik static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last) 1064c6fd2807SJeff Garzik { 1065c6fd2807SJeff Garzik u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS | 1066c6fd2807SJeff Garzik (last ? CRQB_CMD_LAST : 0); 1067c6fd2807SJeff Garzik *cmdw = cpu_to_le16(tmp); 1068c6fd2807SJeff Garzik } 1069c6fd2807SJeff Garzik 1070c6fd2807SJeff Garzik /** 1071c6fd2807SJeff Garzik * mv_qc_prep - Host specific command preparation. 1072c6fd2807SJeff Garzik * @qc: queued command to prepare 1073c6fd2807SJeff Garzik * 1074c6fd2807SJeff Garzik * This routine simply redirects to the general purpose routine 1075c6fd2807SJeff Garzik * if command is not DMA. Else, it handles prep of the CRQB 1076c6fd2807SJeff Garzik * (command request block), does some sanity checking, and calls 1077c6fd2807SJeff Garzik * the SG load routine. 1078c6fd2807SJeff Garzik * 1079c6fd2807SJeff Garzik * LOCKING: 1080c6fd2807SJeff Garzik * Inherited from caller. 1081c6fd2807SJeff Garzik */ 1082c6fd2807SJeff Garzik static void mv_qc_prep(struct ata_queued_cmd *qc) 1083c6fd2807SJeff Garzik { 1084c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1085c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1086c6fd2807SJeff Garzik __le16 *cw; 1087c6fd2807SJeff Garzik struct ata_taskfile *tf; 1088c6fd2807SJeff Garzik u16 flags = 0; 1089c6fd2807SJeff Garzik unsigned in_index; 1090c6fd2807SJeff Garzik 1091c6fd2807SJeff Garzik if (ATA_PROT_DMA != qc->tf.protocol) 1092c6fd2807SJeff Garzik return; 1093c6fd2807SJeff Garzik 1094c6fd2807SJeff Garzik /* Fill in command request block 1095c6fd2807SJeff Garzik */ 1096c6fd2807SJeff Garzik if (!(qc->tf.flags & ATA_TFLAG_WRITE)) 1097c6fd2807SJeff Garzik flags |= CRQB_FLAG_READ; 1098c6fd2807SJeff Garzik WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); 1099c6fd2807SJeff Garzik flags |= qc->tag << CRQB_TAG_SHIFT; 1100c6fd2807SJeff Garzik 1101c6fd2807SJeff Garzik /* get current queue index from hardware */ 1102c6fd2807SJeff Garzik in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS) 1103c6fd2807SJeff Garzik >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; 1104c6fd2807SJeff Garzik 1105c6fd2807SJeff Garzik pp->crqb[in_index].sg_addr = 1106c6fd2807SJeff Garzik cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); 1107c6fd2807SJeff Garzik pp->crqb[in_index].sg_addr_hi = 1108c6fd2807SJeff Garzik cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); 1109c6fd2807SJeff Garzik pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags); 1110c6fd2807SJeff Garzik 1111c6fd2807SJeff Garzik cw = &pp->crqb[in_index].ata_cmd[0]; 1112c6fd2807SJeff Garzik tf = &qc->tf; 1113c6fd2807SJeff Garzik 1114c6fd2807SJeff Garzik /* Sadly, the CRQB cannot accomodate all registers--there are 1115c6fd2807SJeff Garzik * only 11 bytes...so we must pick and choose required 1116c6fd2807SJeff Garzik * registers based on the command. So, we drop feature and 1117c6fd2807SJeff Garzik * hob_feature for [RW] DMA commands, but they are needed for 1118c6fd2807SJeff Garzik * NCQ. NCQ will drop hob_nsect. 1119c6fd2807SJeff Garzik */ 1120c6fd2807SJeff Garzik switch (tf->command) { 1121c6fd2807SJeff Garzik case ATA_CMD_READ: 1122c6fd2807SJeff Garzik case ATA_CMD_READ_EXT: 1123c6fd2807SJeff Garzik case ATA_CMD_WRITE: 1124c6fd2807SJeff Garzik case ATA_CMD_WRITE_EXT: 1125c6fd2807SJeff Garzik case ATA_CMD_WRITE_FUA_EXT: 1126c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0); 1127c6fd2807SJeff Garzik break; 1128c6fd2807SJeff Garzik #ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */ 1129c6fd2807SJeff Garzik case ATA_CMD_FPDMA_READ: 1130c6fd2807SJeff Garzik case ATA_CMD_FPDMA_WRITE: 1131c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); 1132c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0); 1133c6fd2807SJeff Garzik break; 1134c6fd2807SJeff Garzik #endif /* FIXME: remove this line when NCQ added */ 1135c6fd2807SJeff Garzik default: 1136c6fd2807SJeff Garzik /* The only other commands EDMA supports in non-queued and 1137c6fd2807SJeff Garzik * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none 1138c6fd2807SJeff Garzik * of which are defined/used by Linux. If we get here, this 1139c6fd2807SJeff Garzik * driver needs work. 1140c6fd2807SJeff Garzik * 1141c6fd2807SJeff Garzik * FIXME: modify libata to give qc_prep a return value and 1142c6fd2807SJeff Garzik * return error here. 1143c6fd2807SJeff Garzik */ 1144c6fd2807SJeff Garzik BUG_ON(tf->command); 1145c6fd2807SJeff Garzik break; 1146c6fd2807SJeff Garzik } 1147c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0); 1148c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0); 1149c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0); 1150c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0); 1151c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0); 1152c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0); 1153c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0); 1154c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0); 1155c6fd2807SJeff Garzik mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */ 1156c6fd2807SJeff Garzik 1157c6fd2807SJeff Garzik if (!(qc->flags & ATA_QCFLAG_DMAMAP)) 1158c6fd2807SJeff Garzik return; 1159c6fd2807SJeff Garzik mv_fill_sg(qc); 1160c6fd2807SJeff Garzik } 1161c6fd2807SJeff Garzik 1162c6fd2807SJeff Garzik /** 1163c6fd2807SJeff Garzik * mv_qc_prep_iie - Host specific command preparation. 1164c6fd2807SJeff Garzik * @qc: queued command to prepare 1165c6fd2807SJeff Garzik * 1166c6fd2807SJeff Garzik * This routine simply redirects to the general purpose routine 1167c6fd2807SJeff Garzik * if command is not DMA. Else, it handles prep of the CRQB 1168c6fd2807SJeff Garzik * (command request block), does some sanity checking, and calls 1169c6fd2807SJeff Garzik * the SG load routine. 1170c6fd2807SJeff Garzik * 1171c6fd2807SJeff Garzik * LOCKING: 1172c6fd2807SJeff Garzik * Inherited from caller. 1173c6fd2807SJeff Garzik */ 1174c6fd2807SJeff Garzik static void mv_qc_prep_iie(struct ata_queued_cmd *qc) 1175c6fd2807SJeff Garzik { 1176c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1177c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1178c6fd2807SJeff Garzik struct mv_crqb_iie *crqb; 1179c6fd2807SJeff Garzik struct ata_taskfile *tf; 1180c6fd2807SJeff Garzik unsigned in_index; 1181c6fd2807SJeff Garzik u32 flags = 0; 1182c6fd2807SJeff Garzik 1183c6fd2807SJeff Garzik if (ATA_PROT_DMA != qc->tf.protocol) 1184c6fd2807SJeff Garzik return; 1185c6fd2807SJeff Garzik 1186c6fd2807SJeff Garzik /* Fill in Gen IIE command request block 1187c6fd2807SJeff Garzik */ 1188c6fd2807SJeff Garzik if (!(qc->tf.flags & ATA_TFLAG_WRITE)) 1189c6fd2807SJeff Garzik flags |= CRQB_FLAG_READ; 1190c6fd2807SJeff Garzik 1191c6fd2807SJeff Garzik WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); 1192c6fd2807SJeff Garzik flags |= qc->tag << CRQB_TAG_SHIFT; 1193c6fd2807SJeff Garzik 1194c6fd2807SJeff Garzik /* get current queue index from hardware */ 1195c6fd2807SJeff Garzik in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS) 1196c6fd2807SJeff Garzik >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; 1197c6fd2807SJeff Garzik 1198c6fd2807SJeff Garzik crqb = (struct mv_crqb_iie *) &pp->crqb[in_index]; 1199c6fd2807SJeff Garzik crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff); 1200c6fd2807SJeff Garzik crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16); 1201c6fd2807SJeff Garzik crqb->flags = cpu_to_le32(flags); 1202c6fd2807SJeff Garzik 1203c6fd2807SJeff Garzik tf = &qc->tf; 1204c6fd2807SJeff Garzik crqb->ata_cmd[0] = cpu_to_le32( 1205c6fd2807SJeff Garzik (tf->command << 16) | 1206c6fd2807SJeff Garzik (tf->feature << 24) 1207c6fd2807SJeff Garzik ); 1208c6fd2807SJeff Garzik crqb->ata_cmd[1] = cpu_to_le32( 1209c6fd2807SJeff Garzik (tf->lbal << 0) | 1210c6fd2807SJeff Garzik (tf->lbam << 8) | 1211c6fd2807SJeff Garzik (tf->lbah << 16) | 1212c6fd2807SJeff Garzik (tf->device << 24) 1213c6fd2807SJeff Garzik ); 1214c6fd2807SJeff Garzik crqb->ata_cmd[2] = cpu_to_le32( 1215c6fd2807SJeff Garzik (tf->hob_lbal << 0) | 1216c6fd2807SJeff Garzik (tf->hob_lbam << 8) | 1217c6fd2807SJeff Garzik (tf->hob_lbah << 16) | 1218c6fd2807SJeff Garzik (tf->hob_feature << 24) 1219c6fd2807SJeff Garzik ); 1220c6fd2807SJeff Garzik crqb->ata_cmd[3] = cpu_to_le32( 1221c6fd2807SJeff Garzik (tf->nsect << 0) | 1222c6fd2807SJeff Garzik (tf->hob_nsect << 8) 1223c6fd2807SJeff Garzik ); 1224c6fd2807SJeff Garzik 1225c6fd2807SJeff Garzik if (!(qc->flags & ATA_QCFLAG_DMAMAP)) 1226c6fd2807SJeff Garzik return; 1227c6fd2807SJeff Garzik mv_fill_sg(qc); 1228c6fd2807SJeff Garzik } 1229c6fd2807SJeff Garzik 1230c6fd2807SJeff Garzik /** 1231c6fd2807SJeff Garzik * mv_qc_issue - Initiate a command to the host 1232c6fd2807SJeff Garzik * @qc: queued command to start 1233c6fd2807SJeff Garzik * 1234c6fd2807SJeff Garzik * This routine simply redirects to the general purpose routine 1235c6fd2807SJeff Garzik * if command is not DMA. Else, it sanity checks our local 1236c6fd2807SJeff Garzik * caches of the request producer/consumer indices then enables 1237c6fd2807SJeff Garzik * DMA and bumps the request producer index. 1238c6fd2807SJeff Garzik * 1239c6fd2807SJeff Garzik * LOCKING: 1240c6fd2807SJeff Garzik * Inherited from caller. 1241c6fd2807SJeff Garzik */ 1242c6fd2807SJeff Garzik static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) 1243c6fd2807SJeff Garzik { 1244c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(qc->ap); 1245c6fd2807SJeff Garzik struct mv_port_priv *pp = qc->ap->private_data; 1246c6fd2807SJeff Garzik unsigned in_index; 1247c6fd2807SJeff Garzik u32 in_ptr; 1248c6fd2807SJeff Garzik 1249c6fd2807SJeff Garzik if (ATA_PROT_DMA != qc->tf.protocol) { 1250c6fd2807SJeff Garzik /* We're about to send a non-EDMA capable command to the 1251c6fd2807SJeff Garzik * port. Turn off EDMA so there won't be problems accessing 1252c6fd2807SJeff Garzik * shadow block, etc registers. 1253c6fd2807SJeff Garzik */ 1254c6fd2807SJeff Garzik mv_stop_dma(qc->ap); 1255c6fd2807SJeff Garzik return ata_qc_issue_prot(qc); 1256c6fd2807SJeff Garzik } 1257c6fd2807SJeff Garzik 1258c6fd2807SJeff Garzik in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS); 1259c6fd2807SJeff Garzik in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; 1260c6fd2807SJeff Garzik 1261c6fd2807SJeff Garzik /* until we do queuing, the queue should be empty at this point */ 1262c6fd2807SJeff Garzik WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) 1263c6fd2807SJeff Garzik >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); 1264c6fd2807SJeff Garzik 1265c6fd2807SJeff Garzik in_index = mv_inc_q_index(in_index); /* now incr producer index */ 1266c6fd2807SJeff Garzik 1267c6fd2807SJeff Garzik mv_start_dma(port_mmio, pp); 1268c6fd2807SJeff Garzik 1269c6fd2807SJeff Garzik /* and write the request in pointer to kick the EDMA to life */ 1270c6fd2807SJeff Garzik in_ptr &= EDMA_REQ_Q_BASE_LO_MASK; 1271c6fd2807SJeff Garzik in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT; 1272c6fd2807SJeff Garzik writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS); 1273c6fd2807SJeff Garzik 1274c6fd2807SJeff Garzik return 0; 1275c6fd2807SJeff Garzik } 1276c6fd2807SJeff Garzik 1277c6fd2807SJeff Garzik /** 1278c6fd2807SJeff Garzik * mv_get_crpb_status - get status from most recently completed cmd 1279c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 1280c6fd2807SJeff Garzik * 1281c6fd2807SJeff Garzik * This routine is for use when the port is in DMA mode, when it 1282c6fd2807SJeff Garzik * will be using the CRPB (command response block) method of 1283c6fd2807SJeff Garzik * returning command completion information. We check indices 1284c6fd2807SJeff Garzik * are good, grab status, and bump the response consumer index to 1285c6fd2807SJeff Garzik * prove that we're up to date. 1286c6fd2807SJeff Garzik * 1287c6fd2807SJeff Garzik * LOCKING: 1288c6fd2807SJeff Garzik * Inherited from caller. 1289c6fd2807SJeff Garzik */ 1290c6fd2807SJeff Garzik static u8 mv_get_crpb_status(struct ata_port *ap) 1291c6fd2807SJeff Garzik { 1292c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(ap); 1293c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1294c6fd2807SJeff Garzik unsigned out_index; 1295c6fd2807SJeff Garzik u32 out_ptr; 1296c6fd2807SJeff Garzik u8 ata_status; 1297c6fd2807SJeff Garzik 1298c6fd2807SJeff Garzik out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); 1299c6fd2807SJeff Garzik out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; 1300c6fd2807SJeff Garzik 1301c6fd2807SJeff Garzik ata_status = le16_to_cpu(pp->crpb[out_index].flags) 1302c6fd2807SJeff Garzik >> CRPB_FLAG_STATUS_SHIFT; 1303c6fd2807SJeff Garzik 1304c6fd2807SJeff Garzik /* increment our consumer index... */ 1305c6fd2807SJeff Garzik out_index = mv_inc_q_index(out_index); 1306c6fd2807SJeff Garzik 1307c6fd2807SJeff Garzik /* and, until we do NCQ, there should only be 1 CRPB waiting */ 1308c6fd2807SJeff Garzik WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) 1309c6fd2807SJeff Garzik >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK)); 1310c6fd2807SJeff Garzik 1311c6fd2807SJeff Garzik /* write out our inc'd consumer index so EDMA knows we're caught up */ 1312c6fd2807SJeff Garzik out_ptr &= EDMA_RSP_Q_BASE_LO_MASK; 1313c6fd2807SJeff Garzik out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT; 1314c6fd2807SJeff Garzik writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); 1315c6fd2807SJeff Garzik 1316c6fd2807SJeff Garzik /* Return ATA status register for completed CRPB */ 1317c6fd2807SJeff Garzik return ata_status; 1318c6fd2807SJeff Garzik } 1319c6fd2807SJeff Garzik 1320c6fd2807SJeff Garzik /** 1321c6fd2807SJeff Garzik * mv_err_intr - Handle error interrupts on the port 1322c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 1323c6fd2807SJeff Garzik * @reset_allowed: bool: 0 == don't trigger from reset here 1324c6fd2807SJeff Garzik * 1325c6fd2807SJeff Garzik * In most cases, just clear the interrupt and move on. However, 1326c6fd2807SJeff Garzik * some cases require an eDMA reset, which is done right before 1327c6fd2807SJeff Garzik * the COMRESET in mv_phy_reset(). The SERR case requires a 1328c6fd2807SJeff Garzik * clear of pending errors in the SATA SERROR register. Finally, 1329c6fd2807SJeff Garzik * if the port disabled DMA, update our cached copy to match. 1330c6fd2807SJeff Garzik * 1331c6fd2807SJeff Garzik * LOCKING: 1332c6fd2807SJeff Garzik * Inherited from caller. 1333c6fd2807SJeff Garzik */ 1334c6fd2807SJeff Garzik static void mv_err_intr(struct ata_port *ap, int reset_allowed) 1335c6fd2807SJeff Garzik { 1336c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(ap); 1337c6fd2807SJeff Garzik u32 edma_err_cause, serr = 0; 1338c6fd2807SJeff Garzik 1339c6fd2807SJeff Garzik edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 1340c6fd2807SJeff Garzik 1341c6fd2807SJeff Garzik if (EDMA_ERR_SERR & edma_err_cause) { 1342c6fd2807SJeff Garzik sata_scr_read(ap, SCR_ERROR, &serr); 1343c6fd2807SJeff Garzik sata_scr_write_flush(ap, SCR_ERROR, serr); 1344c6fd2807SJeff Garzik } 1345c6fd2807SJeff Garzik if (EDMA_ERR_SELF_DIS & edma_err_cause) { 1346c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1347c6fd2807SJeff Garzik pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; 1348c6fd2807SJeff Garzik } 1349c6fd2807SJeff Garzik DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x " 135044877b4eSTejun Heo "SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr); 1351c6fd2807SJeff Garzik 1352c6fd2807SJeff Garzik /* Clear EDMA now that SERR cleanup done */ 1353c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 1354c6fd2807SJeff Garzik 1355c6fd2807SJeff Garzik /* check for fatal here and recover if needed */ 1356c6fd2807SJeff Garzik if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause)) 1357c6fd2807SJeff Garzik mv_stop_and_reset(ap); 1358c6fd2807SJeff Garzik } 1359c6fd2807SJeff Garzik 1360c6fd2807SJeff Garzik /** 1361c6fd2807SJeff Garzik * mv_host_intr - Handle all interrupts on the given host controller 1362cca3974eSJeff Garzik * @host: host specific structure 1363c6fd2807SJeff Garzik * @relevant: port error bits relevant to this host controller 1364c6fd2807SJeff Garzik * @hc: which host controller we're to look at 1365c6fd2807SJeff Garzik * 1366c6fd2807SJeff Garzik * Read then write clear the HC interrupt status then walk each 1367c6fd2807SJeff Garzik * port connected to the HC and see if it needs servicing. Port 1368c6fd2807SJeff Garzik * success ints are reported in the HC interrupt status reg, the 1369c6fd2807SJeff Garzik * port error ints are reported in the higher level main 1370c6fd2807SJeff Garzik * interrupt status register and thus are passed in via the 1371c6fd2807SJeff Garzik * 'relevant' argument. 1372c6fd2807SJeff Garzik * 1373c6fd2807SJeff Garzik * LOCKING: 1374c6fd2807SJeff Garzik * Inherited from caller. 1375c6fd2807SJeff Garzik */ 1376cca3974eSJeff Garzik static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) 1377c6fd2807SJeff Garzik { 13780d5ff566STejun Heo void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; 1379c6fd2807SJeff Garzik void __iomem *hc_mmio = mv_hc_base(mmio, hc); 1380c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 1381c6fd2807SJeff Garzik u32 hc_irq_cause; 1382c6fd2807SJeff Garzik int shift, port, port0, hard_port, handled; 1383c6fd2807SJeff Garzik unsigned int err_mask; 1384c6fd2807SJeff Garzik 138535177265SJeff Garzik if (hc == 0) 1386c6fd2807SJeff Garzik port0 = 0; 138735177265SJeff Garzik else 1388c6fd2807SJeff Garzik port0 = MV_PORTS_PER_HC; 1389c6fd2807SJeff Garzik 1390c6fd2807SJeff Garzik /* we'll need the HC success int register in most cases */ 1391c6fd2807SJeff Garzik hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); 139235177265SJeff Garzik if (hc_irq_cause) 1393c6fd2807SJeff Garzik writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); 1394c6fd2807SJeff Garzik 1395c6fd2807SJeff Garzik VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", 1396c6fd2807SJeff Garzik hc,relevant,hc_irq_cause); 1397c6fd2807SJeff Garzik 1398c6fd2807SJeff Garzik for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { 1399c6fd2807SJeff Garzik u8 ata_status = 0; 1400cca3974eSJeff Garzik struct ata_port *ap = host->ports[port]; 1401c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1402c6fd2807SJeff Garzik 1403c6fd2807SJeff Garzik hard_port = mv_hardport_from_port(port); /* range 0..3 */ 1404c6fd2807SJeff Garzik handled = 0; /* ensure ata_status is set if handled++ */ 1405c6fd2807SJeff Garzik 1406c6fd2807SJeff Garzik /* Note that DEV_IRQ might happen spuriously during EDMA, 1407c6fd2807SJeff Garzik * and should be ignored in such cases. 1408c6fd2807SJeff Garzik * The cause of this is still under investigation. 1409c6fd2807SJeff Garzik */ 1410c6fd2807SJeff Garzik if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { 1411c6fd2807SJeff Garzik /* EDMA: check for response queue interrupt */ 1412c6fd2807SJeff Garzik if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { 1413c6fd2807SJeff Garzik ata_status = mv_get_crpb_status(ap); 1414c6fd2807SJeff Garzik handled = 1; 1415c6fd2807SJeff Garzik } 1416c6fd2807SJeff Garzik } else { 1417c6fd2807SJeff Garzik /* PIO: check for device (drive) interrupt */ 1418c6fd2807SJeff Garzik if ((DEV_IRQ << hard_port) & hc_irq_cause) { 14190d5ff566STejun Heo ata_status = readb(ap->ioaddr.status_addr); 1420c6fd2807SJeff Garzik handled = 1; 1421c6fd2807SJeff Garzik /* ignore spurious intr if drive still BUSY */ 1422c6fd2807SJeff Garzik if (ata_status & ATA_BUSY) { 1423c6fd2807SJeff Garzik ata_status = 0; 1424c6fd2807SJeff Garzik handled = 0; 1425c6fd2807SJeff Garzik } 1426c6fd2807SJeff Garzik } 1427c6fd2807SJeff Garzik } 1428c6fd2807SJeff Garzik 1429c6fd2807SJeff Garzik if (ap && (ap->flags & ATA_FLAG_DISABLED)) 1430c6fd2807SJeff Garzik continue; 1431c6fd2807SJeff Garzik 1432c6fd2807SJeff Garzik err_mask = ac_err_mask(ata_status); 1433c6fd2807SJeff Garzik 1434c6fd2807SJeff Garzik shift = port << 1; /* (port * 2) */ 1435c6fd2807SJeff Garzik if (port >= MV_PORTS_PER_HC) { 1436c6fd2807SJeff Garzik shift++; /* skip bit 8 in the HC Main IRQ reg */ 1437c6fd2807SJeff Garzik } 1438c6fd2807SJeff Garzik if ((PORT0_ERR << shift) & relevant) { 1439c6fd2807SJeff Garzik mv_err_intr(ap, 1); 1440c6fd2807SJeff Garzik err_mask |= AC_ERR_OTHER; 1441c6fd2807SJeff Garzik handled = 1; 1442c6fd2807SJeff Garzik } 1443c6fd2807SJeff Garzik 1444c6fd2807SJeff Garzik if (handled) { 1445c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 1446c6fd2807SJeff Garzik if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) { 1447c6fd2807SJeff Garzik VPRINTK("port %u IRQ found for qc, " 1448c6fd2807SJeff Garzik "ata_status 0x%x\n", port,ata_status); 1449c6fd2807SJeff Garzik /* mark qc status appropriately */ 1450c6fd2807SJeff Garzik if (!(qc->tf.flags & ATA_TFLAG_POLLING)) { 1451c6fd2807SJeff Garzik qc->err_mask |= err_mask; 1452c6fd2807SJeff Garzik ata_qc_complete(qc); 1453c6fd2807SJeff Garzik } 1454c6fd2807SJeff Garzik } 1455c6fd2807SJeff Garzik } 1456c6fd2807SJeff Garzik } 1457c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1458c6fd2807SJeff Garzik } 1459c6fd2807SJeff Garzik 1460c6fd2807SJeff Garzik /** 1461c6fd2807SJeff Garzik * mv_interrupt - 1462c6fd2807SJeff Garzik * @irq: unused 1463c6fd2807SJeff Garzik * @dev_instance: private data; in this case the host structure 1464c6fd2807SJeff Garzik * @regs: unused 1465c6fd2807SJeff Garzik * 1466c6fd2807SJeff Garzik * Read the read only register to determine if any host 1467c6fd2807SJeff Garzik * controllers have pending interrupts. If so, call lower level 1468c6fd2807SJeff Garzik * routine to handle. Also check for PCI errors which are only 1469c6fd2807SJeff Garzik * reported here. 1470c6fd2807SJeff Garzik * 1471c6fd2807SJeff Garzik * LOCKING: 1472cca3974eSJeff Garzik * This routine holds the host lock while processing pending 1473c6fd2807SJeff Garzik * interrupts. 1474c6fd2807SJeff Garzik */ 14757d12e780SDavid Howells static irqreturn_t mv_interrupt(int irq, void *dev_instance) 1476c6fd2807SJeff Garzik { 1477cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1478c6fd2807SJeff Garzik unsigned int hc, handled = 0, n_hcs; 14790d5ff566STejun Heo void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; 1480c6fd2807SJeff Garzik struct mv_host_priv *hpriv; 1481c6fd2807SJeff Garzik u32 irq_stat; 1482c6fd2807SJeff Garzik 1483c6fd2807SJeff Garzik irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); 1484c6fd2807SJeff Garzik 1485c6fd2807SJeff Garzik /* check the cases where we either have nothing pending or have read 1486c6fd2807SJeff Garzik * a bogus register value which can indicate HW removal or PCI fault 1487c6fd2807SJeff Garzik */ 148835177265SJeff Garzik if (!irq_stat || (0xffffffffU == irq_stat)) 1489c6fd2807SJeff Garzik return IRQ_NONE; 1490c6fd2807SJeff Garzik 1491cca3974eSJeff Garzik n_hcs = mv_get_hc_count(host->ports[0]->flags); 1492cca3974eSJeff Garzik spin_lock(&host->lock); 1493c6fd2807SJeff Garzik 1494c6fd2807SJeff Garzik for (hc = 0; hc < n_hcs; hc++) { 1495c6fd2807SJeff Garzik u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT)); 1496c6fd2807SJeff Garzik if (relevant) { 1497cca3974eSJeff Garzik mv_host_intr(host, relevant, hc); 1498c6fd2807SJeff Garzik handled++; 1499c6fd2807SJeff Garzik } 1500c6fd2807SJeff Garzik } 1501c6fd2807SJeff Garzik 1502cca3974eSJeff Garzik hpriv = host->private_data; 1503c6fd2807SJeff Garzik if (IS_60XX(hpriv)) { 1504c6fd2807SJeff Garzik /* deal with the interrupt coalescing bits */ 1505c6fd2807SJeff Garzik if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) { 1506c6fd2807SJeff Garzik writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO); 1507c6fd2807SJeff Garzik writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI); 1508c6fd2807SJeff Garzik writelfl(0, mmio + MV_IRQ_COAL_CAUSE); 1509c6fd2807SJeff Garzik } 1510c6fd2807SJeff Garzik } 1511c6fd2807SJeff Garzik 1512c6fd2807SJeff Garzik if (PCI_ERR & irq_stat) { 1513c6fd2807SJeff Garzik printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n", 1514c6fd2807SJeff Garzik readl(mmio + PCI_IRQ_CAUSE_OFS)); 1515c6fd2807SJeff Garzik 1516c6fd2807SJeff Garzik DPRINTK("All regs @ PCI error\n"); 1517cca3974eSJeff Garzik mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); 1518c6fd2807SJeff Garzik 1519c6fd2807SJeff Garzik writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); 1520c6fd2807SJeff Garzik handled++; 1521c6fd2807SJeff Garzik } 1522cca3974eSJeff Garzik spin_unlock(&host->lock); 1523c6fd2807SJeff Garzik 1524c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1525c6fd2807SJeff Garzik } 1526c6fd2807SJeff Garzik 1527c6fd2807SJeff Garzik static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port) 1528c6fd2807SJeff Garzik { 1529c6fd2807SJeff Garzik void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port); 1530c6fd2807SJeff Garzik unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL; 1531c6fd2807SJeff Garzik 1532c6fd2807SJeff Garzik return hc_mmio + ofs; 1533c6fd2807SJeff Garzik } 1534c6fd2807SJeff Garzik 1535c6fd2807SJeff Garzik static unsigned int mv5_scr_offset(unsigned int sc_reg_in) 1536c6fd2807SJeff Garzik { 1537c6fd2807SJeff Garzik unsigned int ofs; 1538c6fd2807SJeff Garzik 1539c6fd2807SJeff Garzik switch (sc_reg_in) { 1540c6fd2807SJeff Garzik case SCR_STATUS: 1541c6fd2807SJeff Garzik case SCR_ERROR: 1542c6fd2807SJeff Garzik case SCR_CONTROL: 1543c6fd2807SJeff Garzik ofs = sc_reg_in * sizeof(u32); 1544c6fd2807SJeff Garzik break; 1545c6fd2807SJeff Garzik default: 1546c6fd2807SJeff Garzik ofs = 0xffffffffU; 1547c6fd2807SJeff Garzik break; 1548c6fd2807SJeff Garzik } 1549c6fd2807SJeff Garzik return ofs; 1550c6fd2807SJeff Garzik } 1551c6fd2807SJeff Garzik 1552c6fd2807SJeff Garzik static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) 1553c6fd2807SJeff Garzik { 15540d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; 15550d5ff566STejun Heo void __iomem *addr = mv5_phy_base(mmio, ap->port_no); 1556c6fd2807SJeff Garzik unsigned int ofs = mv5_scr_offset(sc_reg_in); 1557c6fd2807SJeff Garzik 1558c6fd2807SJeff Garzik if (ofs != 0xffffffffU) 15590d5ff566STejun Heo return readl(addr + ofs); 1560c6fd2807SJeff Garzik else 1561c6fd2807SJeff Garzik return (u32) ofs; 1562c6fd2807SJeff Garzik } 1563c6fd2807SJeff Garzik 1564c6fd2807SJeff Garzik static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) 1565c6fd2807SJeff Garzik { 15660d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; 15670d5ff566STejun Heo void __iomem *addr = mv5_phy_base(mmio, ap->port_no); 1568c6fd2807SJeff Garzik unsigned int ofs = mv5_scr_offset(sc_reg_in); 1569c6fd2807SJeff Garzik 1570c6fd2807SJeff Garzik if (ofs != 0xffffffffU) 15710d5ff566STejun Heo writelfl(val, addr + ofs); 1572c6fd2807SJeff Garzik } 1573c6fd2807SJeff Garzik 1574c6fd2807SJeff Garzik static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) 1575c6fd2807SJeff Garzik { 1576c6fd2807SJeff Garzik u8 rev_id; 1577c6fd2807SJeff Garzik int early_5080; 1578c6fd2807SJeff Garzik 1579c6fd2807SJeff Garzik pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 1580c6fd2807SJeff Garzik 1581c6fd2807SJeff Garzik early_5080 = (pdev->device == 0x5080) && (rev_id == 0); 1582c6fd2807SJeff Garzik 1583c6fd2807SJeff Garzik if (!early_5080) { 1584c6fd2807SJeff Garzik u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL); 1585c6fd2807SJeff Garzik tmp |= (1 << 0); 1586c6fd2807SJeff Garzik writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); 1587c6fd2807SJeff Garzik } 1588c6fd2807SJeff Garzik 1589c6fd2807SJeff Garzik mv_reset_pci_bus(pdev, mmio); 1590c6fd2807SJeff Garzik } 1591c6fd2807SJeff Garzik 1592c6fd2807SJeff Garzik static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) 1593c6fd2807SJeff Garzik { 1594c6fd2807SJeff Garzik writel(0x0fcfffff, mmio + MV_FLASH_CTL); 1595c6fd2807SJeff Garzik } 1596c6fd2807SJeff Garzik 1597c6fd2807SJeff Garzik static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, 1598c6fd2807SJeff Garzik void __iomem *mmio) 1599c6fd2807SJeff Garzik { 1600c6fd2807SJeff Garzik void __iomem *phy_mmio = mv5_phy_base(mmio, idx); 1601c6fd2807SJeff Garzik u32 tmp; 1602c6fd2807SJeff Garzik 1603c6fd2807SJeff Garzik tmp = readl(phy_mmio + MV5_PHY_MODE); 1604c6fd2807SJeff Garzik 1605c6fd2807SJeff Garzik hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */ 1606c6fd2807SJeff Garzik hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */ 1607c6fd2807SJeff Garzik } 1608c6fd2807SJeff Garzik 1609c6fd2807SJeff Garzik static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) 1610c6fd2807SJeff Garzik { 1611c6fd2807SJeff Garzik u32 tmp; 1612c6fd2807SJeff Garzik 1613c6fd2807SJeff Garzik writel(0, mmio + MV_GPIO_PORT_CTL); 1614c6fd2807SJeff Garzik 1615c6fd2807SJeff Garzik /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */ 1616c6fd2807SJeff Garzik 1617c6fd2807SJeff Garzik tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL); 1618c6fd2807SJeff Garzik tmp |= ~(1 << 0); 1619c6fd2807SJeff Garzik writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL); 1620c6fd2807SJeff Garzik } 1621c6fd2807SJeff Garzik 1622c6fd2807SJeff Garzik static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, 1623c6fd2807SJeff Garzik unsigned int port) 1624c6fd2807SJeff Garzik { 1625c6fd2807SJeff Garzik void __iomem *phy_mmio = mv5_phy_base(mmio, port); 1626c6fd2807SJeff Garzik const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5); 1627c6fd2807SJeff Garzik u32 tmp; 1628c6fd2807SJeff Garzik int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0); 1629c6fd2807SJeff Garzik 1630c6fd2807SJeff Garzik if (fix_apm_sq) { 1631c6fd2807SJeff Garzik tmp = readl(phy_mmio + MV5_LT_MODE); 1632c6fd2807SJeff Garzik tmp |= (1 << 19); 1633c6fd2807SJeff Garzik writel(tmp, phy_mmio + MV5_LT_MODE); 1634c6fd2807SJeff Garzik 1635c6fd2807SJeff Garzik tmp = readl(phy_mmio + MV5_PHY_CTL); 1636c6fd2807SJeff Garzik tmp &= ~0x3; 1637c6fd2807SJeff Garzik tmp |= 0x1; 1638c6fd2807SJeff Garzik writel(tmp, phy_mmio + MV5_PHY_CTL); 1639c6fd2807SJeff Garzik } 1640c6fd2807SJeff Garzik 1641c6fd2807SJeff Garzik tmp = readl(phy_mmio + MV5_PHY_MODE); 1642c6fd2807SJeff Garzik tmp &= ~mask; 1643c6fd2807SJeff Garzik tmp |= hpriv->signal[port].pre; 1644c6fd2807SJeff Garzik tmp |= hpriv->signal[port].amps; 1645c6fd2807SJeff Garzik writel(tmp, phy_mmio + MV5_PHY_MODE); 1646c6fd2807SJeff Garzik } 1647c6fd2807SJeff Garzik 1648c6fd2807SJeff Garzik 1649c6fd2807SJeff Garzik #undef ZERO 1650c6fd2807SJeff Garzik #define ZERO(reg) writel(0, port_mmio + (reg)) 1651c6fd2807SJeff Garzik static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio, 1652c6fd2807SJeff Garzik unsigned int port) 1653c6fd2807SJeff Garzik { 1654c6fd2807SJeff Garzik void __iomem *port_mmio = mv_port_base(mmio, port); 1655c6fd2807SJeff Garzik 1656c6fd2807SJeff Garzik writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); 1657c6fd2807SJeff Garzik 1658c6fd2807SJeff Garzik mv_channel_reset(hpriv, mmio, port); 1659c6fd2807SJeff Garzik 1660c6fd2807SJeff Garzik ZERO(0x028); /* command */ 1661c6fd2807SJeff Garzik writel(0x11f, port_mmio + EDMA_CFG_OFS); 1662c6fd2807SJeff Garzik ZERO(0x004); /* timer */ 1663c6fd2807SJeff Garzik ZERO(0x008); /* irq err cause */ 1664c6fd2807SJeff Garzik ZERO(0x00c); /* irq err mask */ 1665c6fd2807SJeff Garzik ZERO(0x010); /* rq bah */ 1666c6fd2807SJeff Garzik ZERO(0x014); /* rq inp */ 1667c6fd2807SJeff Garzik ZERO(0x018); /* rq outp */ 1668c6fd2807SJeff Garzik ZERO(0x01c); /* respq bah */ 1669c6fd2807SJeff Garzik ZERO(0x024); /* respq outp */ 1670c6fd2807SJeff Garzik ZERO(0x020); /* respq inp */ 1671c6fd2807SJeff Garzik ZERO(0x02c); /* test control */ 1672c6fd2807SJeff Garzik writel(0xbc, port_mmio + EDMA_IORDY_TMOUT); 1673c6fd2807SJeff Garzik } 1674c6fd2807SJeff Garzik #undef ZERO 1675c6fd2807SJeff Garzik 1676c6fd2807SJeff Garzik #define ZERO(reg) writel(0, hc_mmio + (reg)) 1677c6fd2807SJeff Garzik static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio, 1678c6fd2807SJeff Garzik unsigned int hc) 1679c6fd2807SJeff Garzik { 1680c6fd2807SJeff Garzik void __iomem *hc_mmio = mv_hc_base(mmio, hc); 1681c6fd2807SJeff Garzik u32 tmp; 1682c6fd2807SJeff Garzik 1683c6fd2807SJeff Garzik ZERO(0x00c); 1684c6fd2807SJeff Garzik ZERO(0x010); 1685c6fd2807SJeff Garzik ZERO(0x014); 1686c6fd2807SJeff Garzik ZERO(0x018); 1687c6fd2807SJeff Garzik 1688c6fd2807SJeff Garzik tmp = readl(hc_mmio + 0x20); 1689c6fd2807SJeff Garzik tmp &= 0x1c1c1c1c; 1690c6fd2807SJeff Garzik tmp |= 0x03030303; 1691c6fd2807SJeff Garzik writel(tmp, hc_mmio + 0x20); 1692c6fd2807SJeff Garzik } 1693c6fd2807SJeff Garzik #undef ZERO 1694c6fd2807SJeff Garzik 1695c6fd2807SJeff Garzik static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, 1696c6fd2807SJeff Garzik unsigned int n_hc) 1697c6fd2807SJeff Garzik { 1698c6fd2807SJeff Garzik unsigned int hc, port; 1699c6fd2807SJeff Garzik 1700c6fd2807SJeff Garzik for (hc = 0; hc < n_hc; hc++) { 1701c6fd2807SJeff Garzik for (port = 0; port < MV_PORTS_PER_HC; port++) 1702c6fd2807SJeff Garzik mv5_reset_hc_port(hpriv, mmio, 1703c6fd2807SJeff Garzik (hc * MV_PORTS_PER_HC) + port); 1704c6fd2807SJeff Garzik 1705c6fd2807SJeff Garzik mv5_reset_one_hc(hpriv, mmio, hc); 1706c6fd2807SJeff Garzik } 1707c6fd2807SJeff Garzik 1708c6fd2807SJeff Garzik return 0; 1709c6fd2807SJeff Garzik } 1710c6fd2807SJeff Garzik 1711c6fd2807SJeff Garzik #undef ZERO 1712c6fd2807SJeff Garzik #define ZERO(reg) writel(0, mmio + (reg)) 1713c6fd2807SJeff Garzik static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) 1714c6fd2807SJeff Garzik { 1715c6fd2807SJeff Garzik u32 tmp; 1716c6fd2807SJeff Garzik 1717c6fd2807SJeff Garzik tmp = readl(mmio + MV_PCI_MODE); 1718c6fd2807SJeff Garzik tmp &= 0xff00ffff; 1719c6fd2807SJeff Garzik writel(tmp, mmio + MV_PCI_MODE); 1720c6fd2807SJeff Garzik 1721c6fd2807SJeff Garzik ZERO(MV_PCI_DISC_TIMER); 1722c6fd2807SJeff Garzik ZERO(MV_PCI_MSI_TRIGGER); 1723c6fd2807SJeff Garzik writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); 1724c6fd2807SJeff Garzik ZERO(HC_MAIN_IRQ_MASK_OFS); 1725c6fd2807SJeff Garzik ZERO(MV_PCI_SERR_MASK); 1726c6fd2807SJeff Garzik ZERO(PCI_IRQ_CAUSE_OFS); 1727c6fd2807SJeff Garzik ZERO(PCI_IRQ_MASK_OFS); 1728c6fd2807SJeff Garzik ZERO(MV_PCI_ERR_LOW_ADDRESS); 1729c6fd2807SJeff Garzik ZERO(MV_PCI_ERR_HIGH_ADDRESS); 1730c6fd2807SJeff Garzik ZERO(MV_PCI_ERR_ATTRIBUTE); 1731c6fd2807SJeff Garzik ZERO(MV_PCI_ERR_COMMAND); 1732c6fd2807SJeff Garzik } 1733c6fd2807SJeff Garzik #undef ZERO 1734c6fd2807SJeff Garzik 1735c6fd2807SJeff Garzik static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) 1736c6fd2807SJeff Garzik { 1737c6fd2807SJeff Garzik u32 tmp; 1738c6fd2807SJeff Garzik 1739c6fd2807SJeff Garzik mv5_reset_flash(hpriv, mmio); 1740c6fd2807SJeff Garzik 1741c6fd2807SJeff Garzik tmp = readl(mmio + MV_GPIO_PORT_CTL); 1742c6fd2807SJeff Garzik tmp &= 0x3; 1743c6fd2807SJeff Garzik tmp |= (1 << 5) | (1 << 6); 1744c6fd2807SJeff Garzik writel(tmp, mmio + MV_GPIO_PORT_CTL); 1745c6fd2807SJeff Garzik } 1746c6fd2807SJeff Garzik 1747c6fd2807SJeff Garzik /** 1748c6fd2807SJeff Garzik * mv6_reset_hc - Perform the 6xxx global soft reset 1749c6fd2807SJeff Garzik * @mmio: base address of the HBA 1750c6fd2807SJeff Garzik * 1751c6fd2807SJeff Garzik * This routine only applies to 6xxx parts. 1752c6fd2807SJeff Garzik * 1753c6fd2807SJeff Garzik * LOCKING: 1754c6fd2807SJeff Garzik * Inherited from caller. 1755c6fd2807SJeff Garzik */ 1756c6fd2807SJeff Garzik static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, 1757c6fd2807SJeff Garzik unsigned int n_hc) 1758c6fd2807SJeff Garzik { 1759c6fd2807SJeff Garzik void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS; 1760c6fd2807SJeff Garzik int i, rc = 0; 1761c6fd2807SJeff Garzik u32 t; 1762c6fd2807SJeff Garzik 1763c6fd2807SJeff Garzik /* Following procedure defined in PCI "main command and status 1764c6fd2807SJeff Garzik * register" table. 1765c6fd2807SJeff Garzik */ 1766c6fd2807SJeff Garzik t = readl(reg); 1767c6fd2807SJeff Garzik writel(t | STOP_PCI_MASTER, reg); 1768c6fd2807SJeff Garzik 1769c6fd2807SJeff Garzik for (i = 0; i < 1000; i++) { 1770c6fd2807SJeff Garzik udelay(1); 1771c6fd2807SJeff Garzik t = readl(reg); 1772c6fd2807SJeff Garzik if (PCI_MASTER_EMPTY & t) { 1773c6fd2807SJeff Garzik break; 1774c6fd2807SJeff Garzik } 1775c6fd2807SJeff Garzik } 1776c6fd2807SJeff Garzik if (!(PCI_MASTER_EMPTY & t)) { 1777c6fd2807SJeff Garzik printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); 1778c6fd2807SJeff Garzik rc = 1; 1779c6fd2807SJeff Garzik goto done; 1780c6fd2807SJeff Garzik } 1781c6fd2807SJeff Garzik 1782c6fd2807SJeff Garzik /* set reset */ 1783c6fd2807SJeff Garzik i = 5; 1784c6fd2807SJeff Garzik do { 1785c6fd2807SJeff Garzik writel(t | GLOB_SFT_RST, reg); 1786c6fd2807SJeff Garzik t = readl(reg); 1787c6fd2807SJeff Garzik udelay(1); 1788c6fd2807SJeff Garzik } while (!(GLOB_SFT_RST & t) && (i-- > 0)); 1789c6fd2807SJeff Garzik 1790c6fd2807SJeff Garzik if (!(GLOB_SFT_RST & t)) { 1791c6fd2807SJeff Garzik printk(KERN_ERR DRV_NAME ": can't set global reset\n"); 1792c6fd2807SJeff Garzik rc = 1; 1793c6fd2807SJeff Garzik goto done; 1794c6fd2807SJeff Garzik } 1795c6fd2807SJeff Garzik 1796c6fd2807SJeff Garzik /* clear reset and *reenable the PCI master* (not mentioned in spec) */ 1797c6fd2807SJeff Garzik i = 5; 1798c6fd2807SJeff Garzik do { 1799c6fd2807SJeff Garzik writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg); 1800c6fd2807SJeff Garzik t = readl(reg); 1801c6fd2807SJeff Garzik udelay(1); 1802c6fd2807SJeff Garzik } while ((GLOB_SFT_RST & t) && (i-- > 0)); 1803c6fd2807SJeff Garzik 1804c6fd2807SJeff Garzik if (GLOB_SFT_RST & t) { 1805c6fd2807SJeff Garzik printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); 1806c6fd2807SJeff Garzik rc = 1; 1807c6fd2807SJeff Garzik } 1808c6fd2807SJeff Garzik done: 1809c6fd2807SJeff Garzik return rc; 1810c6fd2807SJeff Garzik } 1811c6fd2807SJeff Garzik 1812c6fd2807SJeff Garzik static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, 1813c6fd2807SJeff Garzik void __iomem *mmio) 1814c6fd2807SJeff Garzik { 1815c6fd2807SJeff Garzik void __iomem *port_mmio; 1816c6fd2807SJeff Garzik u32 tmp; 1817c6fd2807SJeff Garzik 1818c6fd2807SJeff Garzik tmp = readl(mmio + MV_RESET_CFG); 1819c6fd2807SJeff Garzik if ((tmp & (1 << 0)) == 0) { 1820c6fd2807SJeff Garzik hpriv->signal[idx].amps = 0x7 << 8; 1821c6fd2807SJeff Garzik hpriv->signal[idx].pre = 0x1 << 5; 1822c6fd2807SJeff Garzik return; 1823c6fd2807SJeff Garzik } 1824c6fd2807SJeff Garzik 1825c6fd2807SJeff Garzik port_mmio = mv_port_base(mmio, idx); 1826c6fd2807SJeff Garzik tmp = readl(port_mmio + PHY_MODE2); 1827c6fd2807SJeff Garzik 1828c6fd2807SJeff Garzik hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */ 1829c6fd2807SJeff Garzik hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ 1830c6fd2807SJeff Garzik } 1831c6fd2807SJeff Garzik 1832c6fd2807SJeff Garzik static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio) 1833c6fd2807SJeff Garzik { 1834c6fd2807SJeff Garzik writel(0x00000060, mmio + MV_GPIO_PORT_CTL); 1835c6fd2807SJeff Garzik } 1836c6fd2807SJeff Garzik 1837c6fd2807SJeff Garzik static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, 1838c6fd2807SJeff Garzik unsigned int port) 1839c6fd2807SJeff Garzik { 1840c6fd2807SJeff Garzik void __iomem *port_mmio = mv_port_base(mmio, port); 1841c6fd2807SJeff Garzik 1842c6fd2807SJeff Garzik u32 hp_flags = hpriv->hp_flags; 1843c6fd2807SJeff Garzik int fix_phy_mode2 = 1844c6fd2807SJeff Garzik hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); 1845c6fd2807SJeff Garzik int fix_phy_mode4 = 1846c6fd2807SJeff Garzik hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0); 1847c6fd2807SJeff Garzik u32 m2, tmp; 1848c6fd2807SJeff Garzik 1849c6fd2807SJeff Garzik if (fix_phy_mode2) { 1850c6fd2807SJeff Garzik m2 = readl(port_mmio + PHY_MODE2); 1851c6fd2807SJeff Garzik m2 &= ~(1 << 16); 1852c6fd2807SJeff Garzik m2 |= (1 << 31); 1853c6fd2807SJeff Garzik writel(m2, port_mmio + PHY_MODE2); 1854c6fd2807SJeff Garzik 1855c6fd2807SJeff Garzik udelay(200); 1856c6fd2807SJeff Garzik 1857c6fd2807SJeff Garzik m2 = readl(port_mmio + PHY_MODE2); 1858c6fd2807SJeff Garzik m2 &= ~((1 << 16) | (1 << 31)); 1859c6fd2807SJeff Garzik writel(m2, port_mmio + PHY_MODE2); 1860c6fd2807SJeff Garzik 1861c6fd2807SJeff Garzik udelay(200); 1862c6fd2807SJeff Garzik } 1863c6fd2807SJeff Garzik 1864c6fd2807SJeff Garzik /* who knows what this magic does */ 1865c6fd2807SJeff Garzik tmp = readl(port_mmio + PHY_MODE3); 1866c6fd2807SJeff Garzik tmp &= ~0x7F800000; 1867c6fd2807SJeff Garzik tmp |= 0x2A800000; 1868c6fd2807SJeff Garzik writel(tmp, port_mmio + PHY_MODE3); 1869c6fd2807SJeff Garzik 1870c6fd2807SJeff Garzik if (fix_phy_mode4) { 1871c6fd2807SJeff Garzik u32 m4; 1872c6fd2807SJeff Garzik 1873c6fd2807SJeff Garzik m4 = readl(port_mmio + PHY_MODE4); 1874c6fd2807SJeff Garzik 1875c6fd2807SJeff Garzik if (hp_flags & MV_HP_ERRATA_60X1B2) 1876c6fd2807SJeff Garzik tmp = readl(port_mmio + 0x310); 1877c6fd2807SJeff Garzik 1878c6fd2807SJeff Garzik m4 = (m4 & ~(1 << 1)) | (1 << 0); 1879c6fd2807SJeff Garzik 1880c6fd2807SJeff Garzik writel(m4, port_mmio + PHY_MODE4); 1881c6fd2807SJeff Garzik 1882c6fd2807SJeff Garzik if (hp_flags & MV_HP_ERRATA_60X1B2) 1883c6fd2807SJeff Garzik writel(tmp, port_mmio + 0x310); 1884c6fd2807SJeff Garzik } 1885c6fd2807SJeff Garzik 1886c6fd2807SJeff Garzik /* Revert values of pre-emphasis and signal amps to the saved ones */ 1887c6fd2807SJeff Garzik m2 = readl(port_mmio + PHY_MODE2); 1888c6fd2807SJeff Garzik 1889c6fd2807SJeff Garzik m2 &= ~MV_M2_PREAMP_MASK; 1890c6fd2807SJeff Garzik m2 |= hpriv->signal[port].amps; 1891c6fd2807SJeff Garzik m2 |= hpriv->signal[port].pre; 1892c6fd2807SJeff Garzik m2 &= ~(1 << 16); 1893c6fd2807SJeff Garzik 1894c6fd2807SJeff Garzik /* according to mvSata 3.6.1, some IIE values are fixed */ 1895c6fd2807SJeff Garzik if (IS_GEN_IIE(hpriv)) { 1896c6fd2807SJeff Garzik m2 &= ~0xC30FF01F; 1897c6fd2807SJeff Garzik m2 |= 0x0000900F; 1898c6fd2807SJeff Garzik } 1899c6fd2807SJeff Garzik 1900c6fd2807SJeff Garzik writel(m2, port_mmio + PHY_MODE2); 1901c6fd2807SJeff Garzik } 1902c6fd2807SJeff Garzik 1903c6fd2807SJeff Garzik static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, 1904c6fd2807SJeff Garzik unsigned int port_no) 1905c6fd2807SJeff Garzik { 1906c6fd2807SJeff Garzik void __iomem *port_mmio = mv_port_base(mmio, port_no); 1907c6fd2807SJeff Garzik 1908c6fd2807SJeff Garzik writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS); 1909c6fd2807SJeff Garzik 1910c6fd2807SJeff Garzik if (IS_60XX(hpriv)) { 1911c6fd2807SJeff Garzik u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); 1912c6fd2807SJeff Garzik ifctl |= (1 << 7); /* enable gen2i speed */ 1913c6fd2807SJeff Garzik ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */ 1914c6fd2807SJeff Garzik writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); 1915c6fd2807SJeff Garzik } 1916c6fd2807SJeff Garzik 1917c6fd2807SJeff Garzik udelay(25); /* allow reset propagation */ 1918c6fd2807SJeff Garzik 1919c6fd2807SJeff Garzik /* Spec never mentions clearing the bit. Marvell's driver does 1920c6fd2807SJeff Garzik * clear the bit, however. 1921c6fd2807SJeff Garzik */ 1922c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_CMD_OFS); 1923c6fd2807SJeff Garzik 1924c6fd2807SJeff Garzik hpriv->ops->phy_errata(hpriv, mmio, port_no); 1925c6fd2807SJeff Garzik 1926c6fd2807SJeff Garzik if (IS_50XX(hpriv)) 1927c6fd2807SJeff Garzik mdelay(1); 1928c6fd2807SJeff Garzik } 1929c6fd2807SJeff Garzik 1930c6fd2807SJeff Garzik static void mv_stop_and_reset(struct ata_port *ap) 1931c6fd2807SJeff Garzik { 1932cca3974eSJeff Garzik struct mv_host_priv *hpriv = ap->host->private_data; 19330d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; 1934c6fd2807SJeff Garzik 1935c6fd2807SJeff Garzik mv_stop_dma(ap); 1936c6fd2807SJeff Garzik 1937c6fd2807SJeff Garzik mv_channel_reset(hpriv, mmio, ap->port_no); 1938c6fd2807SJeff Garzik 1939c6fd2807SJeff Garzik __mv_phy_reset(ap, 0); 1940c6fd2807SJeff Garzik } 1941c6fd2807SJeff Garzik 1942c6fd2807SJeff Garzik static inline void __msleep(unsigned int msec, int can_sleep) 1943c6fd2807SJeff Garzik { 1944c6fd2807SJeff Garzik if (can_sleep) 1945c6fd2807SJeff Garzik msleep(msec); 1946c6fd2807SJeff Garzik else 1947c6fd2807SJeff Garzik mdelay(msec); 1948c6fd2807SJeff Garzik } 1949c6fd2807SJeff Garzik 1950c6fd2807SJeff Garzik /** 1951c6fd2807SJeff Garzik * __mv_phy_reset - Perform eDMA reset followed by COMRESET 1952c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 1953c6fd2807SJeff Garzik * 1954c6fd2807SJeff Garzik * Part of this is taken from __sata_phy_reset and modified to 1955c6fd2807SJeff Garzik * not sleep since this routine gets called from interrupt level. 1956c6fd2807SJeff Garzik * 1957c6fd2807SJeff Garzik * LOCKING: 1958c6fd2807SJeff Garzik * Inherited from caller. This is coded to safe to call at 1959c6fd2807SJeff Garzik * interrupt level, i.e. it does not sleep. 1960c6fd2807SJeff Garzik */ 1961c6fd2807SJeff Garzik static void __mv_phy_reset(struct ata_port *ap, int can_sleep) 1962c6fd2807SJeff Garzik { 1963c6fd2807SJeff Garzik struct mv_port_priv *pp = ap->private_data; 1964cca3974eSJeff Garzik struct mv_host_priv *hpriv = ap->host->private_data; 1965c6fd2807SJeff Garzik void __iomem *port_mmio = mv_ap_base(ap); 1966c6fd2807SJeff Garzik struct ata_taskfile tf; 1967c6fd2807SJeff Garzik struct ata_device *dev = &ap->device[0]; 1968c6fd2807SJeff Garzik unsigned long timeout; 1969c6fd2807SJeff Garzik int retry = 5; 1970c6fd2807SJeff Garzik u32 sstatus; 1971c6fd2807SJeff Garzik 1972c6fd2807SJeff Garzik VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); 1973c6fd2807SJeff Garzik 1974c6fd2807SJeff Garzik DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " 1975c6fd2807SJeff Garzik "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), 1976c6fd2807SJeff Garzik mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); 1977c6fd2807SJeff Garzik 1978c6fd2807SJeff Garzik /* Issue COMRESET via SControl */ 1979c6fd2807SJeff Garzik comreset_retry: 1980c6fd2807SJeff Garzik sata_scr_write_flush(ap, SCR_CONTROL, 0x301); 1981c6fd2807SJeff Garzik __msleep(1, can_sleep); 1982c6fd2807SJeff Garzik 1983c6fd2807SJeff Garzik sata_scr_write_flush(ap, SCR_CONTROL, 0x300); 1984c6fd2807SJeff Garzik __msleep(20, can_sleep); 1985c6fd2807SJeff Garzik 1986c6fd2807SJeff Garzik timeout = jiffies + msecs_to_jiffies(200); 1987c6fd2807SJeff Garzik do { 1988c6fd2807SJeff Garzik sata_scr_read(ap, SCR_STATUS, &sstatus); 1989dd1dc802SJeff Garzik if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) 1990c6fd2807SJeff Garzik break; 1991c6fd2807SJeff Garzik 1992c6fd2807SJeff Garzik __msleep(1, can_sleep); 1993c6fd2807SJeff Garzik } while (time_before(jiffies, timeout)); 1994c6fd2807SJeff Garzik 1995c6fd2807SJeff Garzik /* work around errata */ 1996c6fd2807SJeff Garzik if (IS_60XX(hpriv) && 1997c6fd2807SJeff Garzik (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) && 1998c6fd2807SJeff Garzik (retry-- > 0)) 1999c6fd2807SJeff Garzik goto comreset_retry; 2000c6fd2807SJeff Garzik 2001c6fd2807SJeff Garzik DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " 2002c6fd2807SJeff Garzik "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), 2003c6fd2807SJeff Garzik mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); 2004c6fd2807SJeff Garzik 2005c6fd2807SJeff Garzik if (ata_port_online(ap)) { 2006c6fd2807SJeff Garzik ata_port_probe(ap); 2007c6fd2807SJeff Garzik } else { 2008c6fd2807SJeff Garzik sata_scr_read(ap, SCR_STATUS, &sstatus); 2009c6fd2807SJeff Garzik ata_port_printk(ap, KERN_INFO, 2010c6fd2807SJeff Garzik "no device found (phy stat %08x)\n", sstatus); 2011c6fd2807SJeff Garzik ata_port_disable(ap); 2012c6fd2807SJeff Garzik return; 2013c6fd2807SJeff Garzik } 2014c6fd2807SJeff Garzik 2015c6fd2807SJeff Garzik /* even after SStatus reflects that device is ready, 2016c6fd2807SJeff Garzik * it seems to take a while for link to be fully 2017c6fd2807SJeff Garzik * established (and thus Status no longer 0x80/0x7F), 2018c6fd2807SJeff Garzik * so we poll a bit for that, here. 2019c6fd2807SJeff Garzik */ 2020c6fd2807SJeff Garzik retry = 20; 2021c6fd2807SJeff Garzik while (1) { 2022c6fd2807SJeff Garzik u8 drv_stat = ata_check_status(ap); 2023c6fd2807SJeff Garzik if ((drv_stat != 0x80) && (drv_stat != 0x7f)) 2024c6fd2807SJeff Garzik break; 2025c6fd2807SJeff Garzik __msleep(500, can_sleep); 2026c6fd2807SJeff Garzik if (retry-- <= 0) 2027c6fd2807SJeff Garzik break; 2028c6fd2807SJeff Garzik } 2029c6fd2807SJeff Garzik 20300d5ff566STejun Heo tf.lbah = readb(ap->ioaddr.lbah_addr); 20310d5ff566STejun Heo tf.lbam = readb(ap->ioaddr.lbam_addr); 20320d5ff566STejun Heo tf.lbal = readb(ap->ioaddr.lbal_addr); 20330d5ff566STejun Heo tf.nsect = readb(ap->ioaddr.nsect_addr); 2034c6fd2807SJeff Garzik 2035c6fd2807SJeff Garzik dev->class = ata_dev_classify(&tf); 2036c6fd2807SJeff Garzik if (!ata_dev_enabled(dev)) { 2037c6fd2807SJeff Garzik VPRINTK("Port disabled post-sig: No device present.\n"); 2038c6fd2807SJeff Garzik ata_port_disable(ap); 2039c6fd2807SJeff Garzik } 2040c6fd2807SJeff Garzik 2041c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 2042c6fd2807SJeff Garzik 2043c6fd2807SJeff Garzik pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; 2044c6fd2807SJeff Garzik 2045c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 2046c6fd2807SJeff Garzik } 2047c6fd2807SJeff Garzik 2048c6fd2807SJeff Garzik static void mv_phy_reset(struct ata_port *ap) 2049c6fd2807SJeff Garzik { 2050c6fd2807SJeff Garzik __mv_phy_reset(ap, 1); 2051c6fd2807SJeff Garzik } 2052c6fd2807SJeff Garzik 2053c6fd2807SJeff Garzik /** 2054c6fd2807SJeff Garzik * mv_eng_timeout - Routine called by libata when SCSI times out I/O 2055c6fd2807SJeff Garzik * @ap: ATA channel to manipulate 2056c6fd2807SJeff Garzik * 2057c6fd2807SJeff Garzik * Intent is to clear all pending error conditions, reset the 2058c6fd2807SJeff Garzik * chip/bus, fail the command, and move on. 2059c6fd2807SJeff Garzik * 2060c6fd2807SJeff Garzik * LOCKING: 2061cca3974eSJeff Garzik * This routine holds the host lock while failing the command. 2062c6fd2807SJeff Garzik */ 2063c6fd2807SJeff Garzik static void mv_eng_timeout(struct ata_port *ap) 2064c6fd2807SJeff Garzik { 20650d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; 2066c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 2067c6fd2807SJeff Garzik unsigned long flags; 2068c6fd2807SJeff Garzik 2069c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n"); 2070c6fd2807SJeff Garzik DPRINTK("All regs @ start of eng_timeout\n"); 20710d5ff566STejun Heo mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev)); 2072c6fd2807SJeff Garzik 2073c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 2074c6fd2807SJeff Garzik printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", 20750d5ff566STejun Heo mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); 2076c6fd2807SJeff Garzik 2077cca3974eSJeff Garzik spin_lock_irqsave(&ap->host->lock, flags); 2078c6fd2807SJeff Garzik mv_err_intr(ap, 0); 2079c6fd2807SJeff Garzik mv_stop_and_reset(ap); 2080cca3974eSJeff Garzik spin_unlock_irqrestore(&ap->host->lock, flags); 2081c6fd2807SJeff Garzik 2082c6fd2807SJeff Garzik WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); 2083c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_ACTIVE) { 2084c6fd2807SJeff Garzik qc->err_mask |= AC_ERR_TIMEOUT; 2085c6fd2807SJeff Garzik ata_eh_qc_complete(qc); 2086c6fd2807SJeff Garzik } 2087c6fd2807SJeff Garzik } 2088c6fd2807SJeff Garzik 2089c6fd2807SJeff Garzik /** 2090c6fd2807SJeff Garzik * mv_port_init - Perform some early initialization on a single port. 2091c6fd2807SJeff Garzik * @port: libata data structure storing shadow register addresses 2092c6fd2807SJeff Garzik * @port_mmio: base address of the port 2093c6fd2807SJeff Garzik * 2094c6fd2807SJeff Garzik * Initialize shadow register mmio addresses, clear outstanding 2095c6fd2807SJeff Garzik * interrupts on the port, and unmask interrupts for the future 2096c6fd2807SJeff Garzik * start of the port. 2097c6fd2807SJeff Garzik * 2098c6fd2807SJeff Garzik * LOCKING: 2099c6fd2807SJeff Garzik * Inherited from caller. 2100c6fd2807SJeff Garzik */ 2101c6fd2807SJeff Garzik static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) 2102c6fd2807SJeff Garzik { 21030d5ff566STejun Heo void __iomem *shd_base = port_mmio + SHD_BLK_OFS; 2104c6fd2807SJeff Garzik unsigned serr_ofs; 2105c6fd2807SJeff Garzik 2106c6fd2807SJeff Garzik /* PIO related setup 2107c6fd2807SJeff Garzik */ 2108c6fd2807SJeff Garzik port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA); 2109c6fd2807SJeff Garzik port->error_addr = 2110c6fd2807SJeff Garzik port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR); 2111c6fd2807SJeff Garzik port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT); 2112c6fd2807SJeff Garzik port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL); 2113c6fd2807SJeff Garzik port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM); 2114c6fd2807SJeff Garzik port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH); 2115c6fd2807SJeff Garzik port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE); 2116c6fd2807SJeff Garzik port->status_addr = 2117c6fd2807SJeff Garzik port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS); 2118c6fd2807SJeff Garzik /* special case: control/altstatus doesn't have ATA_REG_ address */ 2119c6fd2807SJeff Garzik port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; 2120c6fd2807SJeff Garzik 2121c6fd2807SJeff Garzik /* unused: */ 21228d9db2d2SRandy Dunlap port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL; 2123c6fd2807SJeff Garzik 2124c6fd2807SJeff Garzik /* Clear any currently outstanding port interrupt conditions */ 2125c6fd2807SJeff Garzik serr_ofs = mv_scr_offset(SCR_ERROR); 2126c6fd2807SJeff Garzik writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs); 2127c6fd2807SJeff Garzik writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 2128c6fd2807SJeff Garzik 2129c6fd2807SJeff Garzik /* unmask all EDMA error interrupts */ 2130c6fd2807SJeff Garzik writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS); 2131c6fd2807SJeff Garzik 2132c6fd2807SJeff Garzik VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", 2133c6fd2807SJeff Garzik readl(port_mmio + EDMA_CFG_OFS), 2134c6fd2807SJeff Garzik readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS), 2135c6fd2807SJeff Garzik readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS)); 2136c6fd2807SJeff Garzik } 2137c6fd2807SJeff Garzik 21384447d351STejun Heo static int mv_chip_id(struct ata_host *host, unsigned int board_idx) 2139c6fd2807SJeff Garzik { 21404447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 21414447d351STejun Heo struct mv_host_priv *hpriv = host->private_data; 2142c6fd2807SJeff Garzik u8 rev_id; 2143c6fd2807SJeff Garzik u32 hp_flags = hpriv->hp_flags; 2144c6fd2807SJeff Garzik 2145c6fd2807SJeff Garzik pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 2146c6fd2807SJeff Garzik 2147c6fd2807SJeff Garzik switch(board_idx) { 2148c6fd2807SJeff Garzik case chip_5080: 2149c6fd2807SJeff Garzik hpriv->ops = &mv5xxx_ops; 2150c6fd2807SJeff Garzik hp_flags |= MV_HP_50XX; 2151c6fd2807SJeff Garzik 2152c6fd2807SJeff Garzik switch (rev_id) { 2153c6fd2807SJeff Garzik case 0x1: 2154c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB0; 2155c6fd2807SJeff Garzik break; 2156c6fd2807SJeff Garzik case 0x3: 2157c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB2; 2158c6fd2807SJeff Garzik break; 2159c6fd2807SJeff Garzik default: 2160c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 2161c6fd2807SJeff Garzik "Applying 50XXB2 workarounds to unknown rev\n"); 2162c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB2; 2163c6fd2807SJeff Garzik break; 2164c6fd2807SJeff Garzik } 2165c6fd2807SJeff Garzik break; 2166c6fd2807SJeff Garzik 2167c6fd2807SJeff Garzik case chip_504x: 2168c6fd2807SJeff Garzik case chip_508x: 2169c6fd2807SJeff Garzik hpriv->ops = &mv5xxx_ops; 2170c6fd2807SJeff Garzik hp_flags |= MV_HP_50XX; 2171c6fd2807SJeff Garzik 2172c6fd2807SJeff Garzik switch (rev_id) { 2173c6fd2807SJeff Garzik case 0x0: 2174c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB0; 2175c6fd2807SJeff Garzik break; 2176c6fd2807SJeff Garzik case 0x3: 2177c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB2; 2178c6fd2807SJeff Garzik break; 2179c6fd2807SJeff Garzik default: 2180c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 2181c6fd2807SJeff Garzik "Applying B2 workarounds to unknown rev\n"); 2182c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_50XXB2; 2183c6fd2807SJeff Garzik break; 2184c6fd2807SJeff Garzik } 2185c6fd2807SJeff Garzik break; 2186c6fd2807SJeff Garzik 2187c6fd2807SJeff Garzik case chip_604x: 2188c6fd2807SJeff Garzik case chip_608x: 2189c6fd2807SJeff Garzik hpriv->ops = &mv6xxx_ops; 2190c6fd2807SJeff Garzik 2191c6fd2807SJeff Garzik switch (rev_id) { 2192c6fd2807SJeff Garzik case 0x7: 2193c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_60X1B2; 2194c6fd2807SJeff Garzik break; 2195c6fd2807SJeff Garzik case 0x9: 2196c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_60X1C0; 2197c6fd2807SJeff Garzik break; 2198c6fd2807SJeff Garzik default: 2199c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 2200c6fd2807SJeff Garzik "Applying B2 workarounds to unknown rev\n"); 2201c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_60X1B2; 2202c6fd2807SJeff Garzik break; 2203c6fd2807SJeff Garzik } 2204c6fd2807SJeff Garzik break; 2205c6fd2807SJeff Garzik 2206c6fd2807SJeff Garzik case chip_7042: 2207c6fd2807SJeff Garzik case chip_6042: 2208c6fd2807SJeff Garzik hpriv->ops = &mv6xxx_ops; 2209c6fd2807SJeff Garzik 2210c6fd2807SJeff Garzik hp_flags |= MV_HP_GEN_IIE; 2211c6fd2807SJeff Garzik 2212c6fd2807SJeff Garzik switch (rev_id) { 2213c6fd2807SJeff Garzik case 0x0: 2214c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_XX42A0; 2215c6fd2807SJeff Garzik break; 2216c6fd2807SJeff Garzik case 0x1: 2217c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_60X1C0; 2218c6fd2807SJeff Garzik break; 2219c6fd2807SJeff Garzik default: 2220c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 2221c6fd2807SJeff Garzik "Applying 60X1C0 workarounds to unknown rev\n"); 2222c6fd2807SJeff Garzik hp_flags |= MV_HP_ERRATA_60X1C0; 2223c6fd2807SJeff Garzik break; 2224c6fd2807SJeff Garzik } 2225c6fd2807SJeff Garzik break; 2226c6fd2807SJeff Garzik 2227c6fd2807SJeff Garzik default: 2228c6fd2807SJeff Garzik printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx); 2229c6fd2807SJeff Garzik return 1; 2230c6fd2807SJeff Garzik } 2231c6fd2807SJeff Garzik 2232c6fd2807SJeff Garzik hpriv->hp_flags = hp_flags; 2233c6fd2807SJeff Garzik 2234c6fd2807SJeff Garzik return 0; 2235c6fd2807SJeff Garzik } 2236c6fd2807SJeff Garzik 2237c6fd2807SJeff Garzik /** 2238c6fd2807SJeff Garzik * mv_init_host - Perform some early initialization of the host. 22394447d351STejun Heo * @host: ATA host to initialize 22404447d351STejun Heo * @board_idx: controller index 2241c6fd2807SJeff Garzik * 2242c6fd2807SJeff Garzik * If possible, do an early global reset of the host. Then do 2243c6fd2807SJeff Garzik * our port init and clear/unmask all/relevant host interrupts. 2244c6fd2807SJeff Garzik * 2245c6fd2807SJeff Garzik * LOCKING: 2246c6fd2807SJeff Garzik * Inherited from caller. 2247c6fd2807SJeff Garzik */ 22484447d351STejun Heo static int mv_init_host(struct ata_host *host, unsigned int board_idx) 2249c6fd2807SJeff Garzik { 2250c6fd2807SJeff Garzik int rc = 0, n_hc, port, hc; 22514447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 22524447d351STejun Heo void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; 22534447d351STejun Heo struct mv_host_priv *hpriv = host->private_data; 2254c6fd2807SJeff Garzik 2255c6fd2807SJeff Garzik /* global interrupt mask */ 2256c6fd2807SJeff Garzik writel(0, mmio + HC_MAIN_IRQ_MASK_OFS); 2257c6fd2807SJeff Garzik 22584447d351STejun Heo rc = mv_chip_id(host, board_idx); 2259c6fd2807SJeff Garzik if (rc) 2260c6fd2807SJeff Garzik goto done; 2261c6fd2807SJeff Garzik 22624447d351STejun Heo n_hc = mv_get_hc_count(host->ports[0]->flags); 2263c6fd2807SJeff Garzik 22644447d351STejun Heo for (port = 0; port < host->n_ports; port++) 2265c6fd2807SJeff Garzik hpriv->ops->read_preamp(hpriv, port, mmio); 2266c6fd2807SJeff Garzik 2267c6fd2807SJeff Garzik rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc); 2268c6fd2807SJeff Garzik if (rc) 2269c6fd2807SJeff Garzik goto done; 2270c6fd2807SJeff Garzik 2271c6fd2807SJeff Garzik hpriv->ops->reset_flash(hpriv, mmio); 2272c6fd2807SJeff Garzik hpriv->ops->reset_bus(pdev, mmio); 2273c6fd2807SJeff Garzik hpriv->ops->enable_leds(hpriv, mmio); 2274c6fd2807SJeff Garzik 22754447d351STejun Heo for (port = 0; port < host->n_ports; port++) { 2276c6fd2807SJeff Garzik if (IS_60XX(hpriv)) { 2277c6fd2807SJeff Garzik void __iomem *port_mmio = mv_port_base(mmio, port); 2278c6fd2807SJeff Garzik 2279c6fd2807SJeff Garzik u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL); 2280c6fd2807SJeff Garzik ifctl |= (1 << 7); /* enable gen2i speed */ 2281c6fd2807SJeff Garzik ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */ 2282c6fd2807SJeff Garzik writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL); 2283c6fd2807SJeff Garzik } 2284c6fd2807SJeff Garzik 2285c6fd2807SJeff Garzik hpriv->ops->phy_errata(hpriv, mmio, port); 2286c6fd2807SJeff Garzik } 2287c6fd2807SJeff Garzik 22884447d351STejun Heo for (port = 0; port < host->n_ports; port++) { 2289c6fd2807SJeff Garzik void __iomem *port_mmio = mv_port_base(mmio, port); 22904447d351STejun Heo mv_port_init(&host->ports[port]->ioaddr, port_mmio); 2291c6fd2807SJeff Garzik } 2292c6fd2807SJeff Garzik 2293c6fd2807SJeff Garzik for (hc = 0; hc < n_hc; hc++) { 2294c6fd2807SJeff Garzik void __iomem *hc_mmio = mv_hc_base(mmio, hc); 2295c6fd2807SJeff Garzik 2296c6fd2807SJeff Garzik VPRINTK("HC%i: HC config=0x%08x HC IRQ cause " 2297c6fd2807SJeff Garzik "(before clear)=0x%08x\n", hc, 2298c6fd2807SJeff Garzik readl(hc_mmio + HC_CFG_OFS), 2299c6fd2807SJeff Garzik readl(hc_mmio + HC_IRQ_CAUSE_OFS)); 2300c6fd2807SJeff Garzik 2301c6fd2807SJeff Garzik /* Clear any currently outstanding hc interrupt conditions */ 2302c6fd2807SJeff Garzik writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); 2303c6fd2807SJeff Garzik } 2304c6fd2807SJeff Garzik 2305c6fd2807SJeff Garzik /* Clear any currently outstanding host interrupt conditions */ 2306c6fd2807SJeff Garzik writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); 2307c6fd2807SJeff Garzik 2308c6fd2807SJeff Garzik /* and unmask interrupt generation for host regs */ 2309c6fd2807SJeff Garzik writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); 2310fb621e2fSJeff Garzik 2311fb621e2fSJeff Garzik if (IS_50XX(hpriv)) 2312fb621e2fSJeff Garzik writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); 2313fb621e2fSJeff Garzik else 2314c6fd2807SJeff Garzik writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); 2315c6fd2807SJeff Garzik 2316c6fd2807SJeff Garzik VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " 2317c6fd2807SJeff Garzik "PCI int cause/mask=0x%08x/0x%08x\n", 2318c6fd2807SJeff Garzik readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), 2319c6fd2807SJeff Garzik readl(mmio + HC_MAIN_IRQ_MASK_OFS), 2320c6fd2807SJeff Garzik readl(mmio + PCI_IRQ_CAUSE_OFS), 2321c6fd2807SJeff Garzik readl(mmio + PCI_IRQ_MASK_OFS)); 2322c6fd2807SJeff Garzik 2323c6fd2807SJeff Garzik done: 2324c6fd2807SJeff Garzik return rc; 2325c6fd2807SJeff Garzik } 2326c6fd2807SJeff Garzik 2327c6fd2807SJeff Garzik /** 2328c6fd2807SJeff Garzik * mv_print_info - Dump key info to kernel log for perusal. 23294447d351STejun Heo * @host: ATA host to print info about 2330c6fd2807SJeff Garzik * 2331c6fd2807SJeff Garzik * FIXME: complete this. 2332c6fd2807SJeff Garzik * 2333c6fd2807SJeff Garzik * LOCKING: 2334c6fd2807SJeff Garzik * Inherited from caller. 2335c6fd2807SJeff Garzik */ 23364447d351STejun Heo static void mv_print_info(struct ata_host *host) 2337c6fd2807SJeff Garzik { 23384447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 23394447d351STejun Heo struct mv_host_priv *hpriv = host->private_data; 2340c6fd2807SJeff Garzik u8 rev_id, scc; 2341*c1e4fe71SJeff Garzik const char *scc_s, *gen; 2342c6fd2807SJeff Garzik 2343c6fd2807SJeff Garzik /* Use this to determine the HW stepping of the chip so we know 2344c6fd2807SJeff Garzik * what errata to workaround 2345c6fd2807SJeff Garzik */ 2346c6fd2807SJeff Garzik pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); 2347c6fd2807SJeff Garzik 2348c6fd2807SJeff Garzik pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc); 2349c6fd2807SJeff Garzik if (scc == 0) 2350c6fd2807SJeff Garzik scc_s = "SCSI"; 2351c6fd2807SJeff Garzik else if (scc == 0x01) 2352c6fd2807SJeff Garzik scc_s = "RAID"; 2353c6fd2807SJeff Garzik else 2354*c1e4fe71SJeff Garzik scc_s = "?"; 2355*c1e4fe71SJeff Garzik 2356*c1e4fe71SJeff Garzik if (IS_GEN_I(hpriv)) 2357*c1e4fe71SJeff Garzik gen = "I"; 2358*c1e4fe71SJeff Garzik else if (IS_GEN_II(hpriv)) 2359*c1e4fe71SJeff Garzik gen = "II"; 2360*c1e4fe71SJeff Garzik else if (IS_GEN_IIE(hpriv)) 2361*c1e4fe71SJeff Garzik gen = "IIE"; 2362*c1e4fe71SJeff Garzik else 2363*c1e4fe71SJeff Garzik gen = "?"; 2364c6fd2807SJeff Garzik 2365c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2366*c1e4fe71SJeff Garzik "Gen-%s %u slots %u ports %s mode IRQ via %s\n", 2367*c1e4fe71SJeff Garzik gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports, 2368c6fd2807SJeff Garzik scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx"); 2369c6fd2807SJeff Garzik } 2370c6fd2807SJeff Garzik 2371c6fd2807SJeff Garzik /** 2372c6fd2807SJeff Garzik * mv_init_one - handle a positive probe of a Marvell host 2373c6fd2807SJeff Garzik * @pdev: PCI device found 2374c6fd2807SJeff Garzik * @ent: PCI device ID entry for the matched host 2375c6fd2807SJeff Garzik * 2376c6fd2807SJeff Garzik * LOCKING: 2377c6fd2807SJeff Garzik * Inherited from caller. 2378c6fd2807SJeff Garzik */ 2379c6fd2807SJeff Garzik static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2380c6fd2807SJeff Garzik { 2381c6fd2807SJeff Garzik static int printed_version = 0; 2382c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int)ent->driver_data; 23834447d351STejun Heo const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL }; 23844447d351STejun Heo struct ata_host *host; 23854447d351STejun Heo struct mv_host_priv *hpriv; 23864447d351STejun Heo int n_ports, rc; 2387c6fd2807SJeff Garzik 2388c6fd2807SJeff Garzik if (!printed_version++) 2389c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 2390c6fd2807SJeff Garzik 23914447d351STejun Heo /* allocate host */ 23924447d351STejun Heo n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC; 23934447d351STejun Heo 23944447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 23954447d351STejun Heo hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); 23964447d351STejun Heo if (!host || !hpriv) 23974447d351STejun Heo return -ENOMEM; 23984447d351STejun Heo host->private_data = hpriv; 23994447d351STejun Heo 24004447d351STejun Heo /* acquire resources */ 240124dc5f33STejun Heo rc = pcim_enable_device(pdev); 240224dc5f33STejun Heo if (rc) 2403c6fd2807SJeff Garzik return rc; 2404c6fd2807SJeff Garzik 24050d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME); 24060d5ff566STejun Heo if (rc == -EBUSY) 240724dc5f33STejun Heo pcim_pin_device(pdev); 24080d5ff566STejun Heo if (rc) 240924dc5f33STejun Heo return rc; 24104447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 2411c6fd2807SJeff Garzik 2412d88184fbSJeff Garzik rc = pci_go_64(pdev); 2413d88184fbSJeff Garzik if (rc) 2414d88184fbSJeff Garzik return rc; 2415d88184fbSJeff Garzik 2416c6fd2807SJeff Garzik /* initialize adapter */ 24174447d351STejun Heo rc = mv_init_host(host, board_idx); 241824dc5f33STejun Heo if (rc) 241924dc5f33STejun Heo return rc; 2420c6fd2807SJeff Garzik 2421c6fd2807SJeff Garzik /* Enable interrupts */ 24226a59dcf8STejun Heo if (msi && pci_enable_msi(pdev)) 2423c6fd2807SJeff Garzik pci_intx(pdev, 1); 2424c6fd2807SJeff Garzik 2425c6fd2807SJeff Garzik mv_dump_pci_cfg(pdev, 0x68); 24264447d351STejun Heo mv_print_info(host); 2427c6fd2807SJeff Garzik 24284447d351STejun Heo pci_set_master(pdev); 24294447d351STejun Heo return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED, 24304447d351STejun Heo &mv_sht); 2431c6fd2807SJeff Garzik } 2432c6fd2807SJeff Garzik 2433c6fd2807SJeff Garzik static int __init mv_init(void) 2434c6fd2807SJeff Garzik { 2435c6fd2807SJeff Garzik return pci_register_driver(&mv_pci_driver); 2436c6fd2807SJeff Garzik } 2437c6fd2807SJeff Garzik 2438c6fd2807SJeff Garzik static void __exit mv_exit(void) 2439c6fd2807SJeff Garzik { 2440c6fd2807SJeff Garzik pci_unregister_driver(&mv_pci_driver); 2441c6fd2807SJeff Garzik } 2442c6fd2807SJeff Garzik 2443c6fd2807SJeff Garzik MODULE_AUTHOR("Brett Russ"); 2444c6fd2807SJeff Garzik MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers"); 2445c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2446c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, mv_pci_tbl); 2447c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2448c6fd2807SJeff Garzik 2449c6fd2807SJeff Garzik module_param(msi, int, 0444); 2450c6fd2807SJeff Garzik MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)"); 2451c6fd2807SJeff Garzik 2452c6fd2807SJeff Garzik module_init(mv_init); 2453c6fd2807SJeff Garzik module_exit(mv_exit); 2454