1c6fd2807SJeff Garzik /* 2c6fd2807SJeff Garzik * ahci.c - AHCI SATA support 3c6fd2807SJeff Garzik * 4c6fd2807SJeff Garzik * Maintained by: Jeff Garzik <jgarzik@pobox.com> 5c6fd2807SJeff Garzik * Please ALWAYS copy linux-ide@vger.kernel.org 6c6fd2807SJeff Garzik * on emails. 7c6fd2807SJeff Garzik * 8c6fd2807SJeff Garzik * Copyright 2004-2005 Red Hat, Inc. 9c6fd2807SJeff Garzik * 10c6fd2807SJeff Garzik * 11c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 12c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 13c6fd2807SJeff Garzik * the Free Software Foundation; either version 2, or (at your option) 14c6fd2807SJeff Garzik * any later version. 15c6fd2807SJeff Garzik * 16c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 17c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 18c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19c6fd2807SJeff Garzik * GNU General Public License for more details. 20c6fd2807SJeff Garzik * 21c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 22c6fd2807SJeff Garzik * along with this program; see the file COPYING. If not, write to 23c6fd2807SJeff Garzik * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 24c6fd2807SJeff Garzik * 25c6fd2807SJeff Garzik * 26c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 27c6fd2807SJeff Garzik * as Documentation/DocBook/libata.* 28c6fd2807SJeff Garzik * 29c6fd2807SJeff Garzik * AHCI hardware documentation: 30c6fd2807SJeff Garzik * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf 31c6fd2807SJeff Garzik * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf 32c6fd2807SJeff Garzik * 33c6fd2807SJeff Garzik */ 34c6fd2807SJeff Garzik 35c6fd2807SJeff Garzik #include <linux/kernel.h> 36c6fd2807SJeff Garzik #include <linux/module.h> 37c6fd2807SJeff Garzik #include <linux/pci.h> 38c6fd2807SJeff Garzik #include <linux/init.h> 39c6fd2807SJeff Garzik #include <linux/blkdev.h> 40c6fd2807SJeff Garzik #include <linux/delay.h> 41c6fd2807SJeff Garzik #include <linux/interrupt.h> 42c6fd2807SJeff Garzik #include <linux/sched.h> 43c6fd2807SJeff Garzik #include <linux/dma-mapping.h> 44c6fd2807SJeff Garzik #include <linux/device.h> 45c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h> 47c6fd2807SJeff Garzik #include <linux/libata.h> 48c6fd2807SJeff Garzik #include <asm/io.h> 49c6fd2807SJeff Garzik 50c6fd2807SJeff Garzik #define DRV_NAME "ahci" 51c6fd2807SJeff Garzik #define DRV_VERSION "2.0" 52c6fd2807SJeff Garzik 53c6fd2807SJeff Garzik 54c6fd2807SJeff Garzik enum { 55c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 56648a88beSTejun Heo AHCI_MAX_PORTS = 32, 57c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 58c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 59c6fd2807SJeff Garzik AHCI_USE_CLUSTERING = 0, 60c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 61c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 62c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 63c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 64c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 65c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 66c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 67c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 68c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 69c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 70c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 71c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 72c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 73c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 74c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 75c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 76c6fd2807SJeff Garzik 77c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 780291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 79c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 80c6fd2807SJeff Garzik 81c6fd2807SJeff Garzik board_ahci = 0, 82648a88beSTejun Heo board_ahci_pi = 1, 83648a88beSTejun Heo board_ahci_vt8251 = 2, 84648a88beSTejun Heo board_ahci_ign_iferr = 3, 85c6fd2807SJeff Garzik 86c6fd2807SJeff Garzik /* global controller registers */ 87c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 88c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 89c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 90c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 91c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 92c6fd2807SJeff Garzik 93c6fd2807SJeff Garzik /* HOST_CTL bits */ 94c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 95c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 96c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 97c6fd2807SJeff Garzik 98c6fd2807SJeff Garzik /* HOST_CAP bits */ 99c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 100c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 101c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 102c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 103c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 104c6fd2807SJeff Garzik 105c6fd2807SJeff Garzik /* registers for each SATA port */ 106c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 107c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 108c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 109c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 110c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 111c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 112c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 113c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 114c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 115c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 116c6fd2807SJeff Garzik PORT_SCR = 0x28, /* SATA phy register block */ 117c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 118c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 119c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 120c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 121c6fd2807SJeff Garzik 122c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 123c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 124c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 125c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 126c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 127c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 128c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 129c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 130c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 131c6fd2807SJeff Garzik 132c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 133c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 134c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 135c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 136c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 137c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 138c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 139c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 140c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 141c6fd2807SJeff Garzik 142c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 143c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 144c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 145c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 146c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS, 147c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 148c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 149c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 150c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 151c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 152c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 153c6fd2807SJeff Garzik 154c6fd2807SJeff Garzik /* PORT_CMD bits */ 155c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 156c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 157c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 158c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 159c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 160c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 161c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 162c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 163c6fd2807SJeff Garzik 164c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 165c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 166c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 167c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 168c6fd2807SJeff Garzik 169c6fd2807SJeff Garzik /* hpriv->flags bits */ 170c6fd2807SJeff Garzik AHCI_FLAG_MSI = (1 << 0), 171c6fd2807SJeff Garzik 172c6fd2807SJeff Garzik /* ap->flags bits */ 1734aeb0e32STejun Heo AHCI_FLAG_NO_NCQ = (1 << 24), 1744aeb0e32STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ 175648a88beSTejun Heo AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ 176c6fd2807SJeff Garzik }; 177c6fd2807SJeff Garzik 178c6fd2807SJeff Garzik struct ahci_cmd_hdr { 179c6fd2807SJeff Garzik u32 opts; 180c6fd2807SJeff Garzik u32 status; 181c6fd2807SJeff Garzik u32 tbl_addr; 182c6fd2807SJeff Garzik u32 tbl_addr_hi; 183c6fd2807SJeff Garzik u32 reserved[4]; 184c6fd2807SJeff Garzik }; 185c6fd2807SJeff Garzik 186c6fd2807SJeff Garzik struct ahci_sg { 187c6fd2807SJeff Garzik u32 addr; 188c6fd2807SJeff Garzik u32 addr_hi; 189c6fd2807SJeff Garzik u32 reserved; 190c6fd2807SJeff Garzik u32 flags_size; 191c6fd2807SJeff Garzik }; 192c6fd2807SJeff Garzik 193c6fd2807SJeff Garzik struct ahci_host_priv { 194c6fd2807SJeff Garzik unsigned long flags; 195c6fd2807SJeff Garzik u32 cap; /* cache of HOST_CAP register */ 196c6fd2807SJeff Garzik u32 port_map; /* cache of HOST_PORTS_IMPL reg */ 197c6fd2807SJeff Garzik }; 198c6fd2807SJeff Garzik 199c6fd2807SJeff Garzik struct ahci_port_priv { 200c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 201c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 202c6fd2807SJeff Garzik void *cmd_tbl; 203c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 204c6fd2807SJeff Garzik void *rx_fis; 205c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2060291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2070291f95fSTejun Heo int ncq_saw_spurious_sdb_cnt; 2080291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2090291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 210c6fd2807SJeff Garzik }; 211c6fd2807SJeff Garzik 212c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); 213c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 214c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 215c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 2167d12e780SDavid Howells static irqreturn_t ahci_interrupt (int irq, void *dev_instance); 217c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap); 218c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 219c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 220c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 221c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 222c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap); 223c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 224c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 225c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 226ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap); 227c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 228c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 229c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 230c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 231c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 232c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev); 233c6fd2807SJeff Garzik 234c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 235c6fd2807SJeff Garzik .module = THIS_MODULE, 236c6fd2807SJeff Garzik .name = DRV_NAME, 237c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 238c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 239c6fd2807SJeff Garzik .change_queue_depth = ata_scsi_change_queue_depth, 240c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 241c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 242c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 243c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 244c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 245c6fd2807SJeff Garzik .use_clustering = AHCI_USE_CLUSTERING, 246c6fd2807SJeff Garzik .proc_name = DRV_NAME, 247c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 248c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 249c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 250c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 251c6fd2807SJeff Garzik .suspend = ata_scsi_device_suspend, 252c6fd2807SJeff Garzik .resume = ata_scsi_device_resume, 253c6fd2807SJeff Garzik }; 254c6fd2807SJeff Garzik 255c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = { 256c6fd2807SJeff Garzik .port_disable = ata_port_disable, 257c6fd2807SJeff Garzik 258c6fd2807SJeff Garzik .check_status = ahci_check_status, 259c6fd2807SJeff Garzik .check_altstatus = ahci_check_status, 260c6fd2807SJeff Garzik .dev_select = ata_noop_dev_select, 261c6fd2807SJeff Garzik 262c6fd2807SJeff Garzik .tf_read = ahci_tf_read, 263c6fd2807SJeff Garzik 264c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 265c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 266c6fd2807SJeff Garzik 267c6fd2807SJeff Garzik .irq_handler = ahci_interrupt, 268c6fd2807SJeff Garzik .irq_clear = ahci_irq_clear, 269c6fd2807SJeff Garzik 270c6fd2807SJeff Garzik .scr_read = ahci_scr_read, 271c6fd2807SJeff Garzik .scr_write = ahci_scr_write, 272c6fd2807SJeff Garzik 273c6fd2807SJeff Garzik .freeze = ahci_freeze, 274c6fd2807SJeff Garzik .thaw = ahci_thaw, 275c6fd2807SJeff Garzik 276c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 277c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 278c6fd2807SJeff Garzik 279c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 280c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 281c6fd2807SJeff Garzik 282c6fd2807SJeff Garzik .port_start = ahci_port_start, 283c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 284c6fd2807SJeff Garzik }; 285c6fd2807SJeff Garzik 286ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = { 287ad616ffbSTejun Heo .port_disable = ata_port_disable, 288ad616ffbSTejun Heo 289ad616ffbSTejun Heo .check_status = ahci_check_status, 290ad616ffbSTejun Heo .check_altstatus = ahci_check_status, 291ad616ffbSTejun Heo .dev_select = ata_noop_dev_select, 292ad616ffbSTejun Heo 293ad616ffbSTejun Heo .tf_read = ahci_tf_read, 294ad616ffbSTejun Heo 295ad616ffbSTejun Heo .qc_prep = ahci_qc_prep, 296ad616ffbSTejun Heo .qc_issue = ahci_qc_issue, 297ad616ffbSTejun Heo 298ad616ffbSTejun Heo .irq_handler = ahci_interrupt, 299ad616ffbSTejun Heo .irq_clear = ahci_irq_clear, 300ad616ffbSTejun Heo 301ad616ffbSTejun Heo .scr_read = ahci_scr_read, 302ad616ffbSTejun Heo .scr_write = ahci_scr_write, 303ad616ffbSTejun Heo 304ad616ffbSTejun Heo .freeze = ahci_freeze, 305ad616ffbSTejun Heo .thaw = ahci_thaw, 306ad616ffbSTejun Heo 307ad616ffbSTejun Heo .error_handler = ahci_vt8251_error_handler, 308ad616ffbSTejun Heo .post_internal_cmd = ahci_post_internal_cmd, 309ad616ffbSTejun Heo 310ad616ffbSTejun Heo .port_suspend = ahci_port_suspend, 311ad616ffbSTejun Heo .port_resume = ahci_port_resume, 312ad616ffbSTejun Heo 313ad616ffbSTejun Heo .port_start = ahci_port_start, 314ad616ffbSTejun Heo .port_stop = ahci_port_stop, 315ad616ffbSTejun Heo }; 316ad616ffbSTejun Heo 317c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 318c6fd2807SJeff Garzik /* board_ahci */ 319c6fd2807SJeff Garzik { 320c6fd2807SJeff Garzik .sht = &ahci_sht, 321cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 322c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 323c6fd2807SJeff Garzik ATA_FLAG_SKIP_D2H_BSY, 324c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 325c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 326c6fd2807SJeff Garzik .port_ops = &ahci_ops, 327c6fd2807SJeff Garzik }, 328648a88beSTejun Heo /* board_ahci_pi */ 329648a88beSTejun Heo { 330648a88beSTejun Heo .sht = &ahci_sht, 331648a88beSTejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 332648a88beSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 333648a88beSTejun Heo ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, 334648a88beSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 335648a88beSTejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 336648a88beSTejun Heo .port_ops = &ahci_ops, 337648a88beSTejun Heo }, 338c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 339c6fd2807SJeff Garzik { 340c6fd2807SJeff Garzik .sht = &ahci_sht, 341cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 342c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 343ad616ffbSTejun Heo ATA_FLAG_SKIP_D2H_BSY | 344ad616ffbSTejun Heo ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, 345c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 346c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 347ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 348c6fd2807SJeff Garzik }, 34941669553STejun Heo /* board_ahci_ign_iferr */ 35041669553STejun Heo { 35141669553STejun Heo .sht = &ahci_sht, 35241669553STejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 35341669553STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 35441669553STejun Heo ATA_FLAG_SKIP_D2H_BSY | 35541669553STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR, 35641669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 35741669553STejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 35841669553STejun Heo .port_ops = &ahci_ops, 35941669553STejun Heo }, 360c6fd2807SJeff Garzik }; 361c6fd2807SJeff Garzik 362c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 363c6fd2807SJeff Garzik /* Intel */ 36454bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 36554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 36654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 36754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 36854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 36982490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 37054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 37154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 37254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 37354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 374648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ 375648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ 376648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ 377648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ 378648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ 379648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ 380648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ 381648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ 382648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ 383648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ 384648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ 385648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ 386648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ 387648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ 388648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ 389648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ 390c6fd2807SJeff Garzik 391c6fd2807SJeff Garzik /* JMicron */ 39241669553STejun Heo { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */ 39341669553STejun Heo { PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */ 39441669553STejun Heo { PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */ 39541669553STejun Heo { PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */ 39641669553STejun Heo { PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */ 397c6fd2807SJeff Garzik 398c6fd2807SJeff Garzik /* ATI */ 39954bb3a94SJeff Garzik { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */ 40054bb3a94SJeff Garzik { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */ 401c6fd2807SJeff Garzik 402c6fd2807SJeff Garzik /* VIA */ 40354bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 404c6fd2807SJeff Garzik 405c6fd2807SJeff Garzik /* NVIDIA */ 40654bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ 40754bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ 40854bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ 40954bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ 4106fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ 4116fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ 4126fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ 4136fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ 4146fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 4156fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 4166fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 4176fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 418895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 419895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 420895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 421895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 422895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 423895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 424895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 425895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 426c6fd2807SJeff Garzik 427c6fd2807SJeff Garzik /* SiS */ 42854bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 42954bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 43054bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 431c6fd2807SJeff Garzik 432415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 433415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 434*c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 435415ae2b5SJeff Garzik 436c6fd2807SJeff Garzik { } /* terminate list */ 437c6fd2807SJeff Garzik }; 438c6fd2807SJeff Garzik 439c6fd2807SJeff Garzik 440c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 441c6fd2807SJeff Garzik .name = DRV_NAME, 442c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 443c6fd2807SJeff Garzik .probe = ahci_init_one, 444c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 445c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 446c6fd2807SJeff Garzik .remove = ahci_remove_one, 447c6fd2807SJeff Garzik }; 448c6fd2807SJeff Garzik 449c6fd2807SJeff Garzik 45098fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 45198fa4b60STejun Heo { 45298fa4b60STejun Heo return (cap & 0x1f) + 1; 45398fa4b60STejun Heo } 45498fa4b60STejun Heo 455c6fd2807SJeff Garzik static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) 456c6fd2807SJeff Garzik { 457c6fd2807SJeff Garzik return base + 0x100 + (port * 0x80); 458c6fd2807SJeff Garzik } 459c6fd2807SJeff Garzik 460c6fd2807SJeff Garzik static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port) 461c6fd2807SJeff Garzik { 462c6fd2807SJeff Garzik return (void __iomem *) ahci_port_base_ul((unsigned long)base, port); 463c6fd2807SJeff Garzik } 464c6fd2807SJeff Garzik 465c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) 466c6fd2807SJeff Garzik { 467c6fd2807SJeff Garzik unsigned int sc_reg; 468c6fd2807SJeff Garzik 469c6fd2807SJeff Garzik switch (sc_reg_in) { 470c6fd2807SJeff Garzik case SCR_STATUS: sc_reg = 0; break; 471c6fd2807SJeff Garzik case SCR_CONTROL: sc_reg = 1; break; 472c6fd2807SJeff Garzik case SCR_ERROR: sc_reg = 2; break; 473c6fd2807SJeff Garzik case SCR_ACTIVE: sc_reg = 3; break; 474c6fd2807SJeff Garzik default: 475c6fd2807SJeff Garzik return 0xffffffffU; 476c6fd2807SJeff Garzik } 477c6fd2807SJeff Garzik 478c6fd2807SJeff Garzik return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); 479c6fd2807SJeff Garzik } 480c6fd2807SJeff Garzik 481c6fd2807SJeff Garzik 482c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, 483c6fd2807SJeff Garzik u32 val) 484c6fd2807SJeff Garzik { 485c6fd2807SJeff Garzik unsigned int sc_reg; 486c6fd2807SJeff Garzik 487c6fd2807SJeff Garzik switch (sc_reg_in) { 488c6fd2807SJeff Garzik case SCR_STATUS: sc_reg = 0; break; 489c6fd2807SJeff Garzik case SCR_CONTROL: sc_reg = 1; break; 490c6fd2807SJeff Garzik case SCR_ERROR: sc_reg = 2; break; 491c6fd2807SJeff Garzik case SCR_ACTIVE: sc_reg = 3; break; 492c6fd2807SJeff Garzik default: 493c6fd2807SJeff Garzik return; 494c6fd2807SJeff Garzik } 495c6fd2807SJeff Garzik 496c6fd2807SJeff Garzik writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); 497c6fd2807SJeff Garzik } 498c6fd2807SJeff Garzik 499c6fd2807SJeff Garzik static void ahci_start_engine(void __iomem *port_mmio) 500c6fd2807SJeff Garzik { 501c6fd2807SJeff Garzik u32 tmp; 502c6fd2807SJeff Garzik 503c6fd2807SJeff Garzik /* start DMA */ 504c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 505c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 506c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 507c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 508c6fd2807SJeff Garzik } 509c6fd2807SJeff Garzik 510c6fd2807SJeff Garzik static int ahci_stop_engine(void __iomem *port_mmio) 511c6fd2807SJeff Garzik { 512c6fd2807SJeff Garzik u32 tmp; 513c6fd2807SJeff Garzik 514c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 515c6fd2807SJeff Garzik 516c6fd2807SJeff Garzik /* check if the HBA is idle */ 517c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 518c6fd2807SJeff Garzik return 0; 519c6fd2807SJeff Garzik 520c6fd2807SJeff Garzik /* setting HBA to idle */ 521c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 522c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 523c6fd2807SJeff Garzik 524c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 525c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 526c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 527c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 528c6fd2807SJeff Garzik return -EIO; 529c6fd2807SJeff Garzik 530c6fd2807SJeff Garzik return 0; 531c6fd2807SJeff Garzik } 532c6fd2807SJeff Garzik 533c6fd2807SJeff Garzik static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap, 534c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) 535c6fd2807SJeff Garzik { 536c6fd2807SJeff Garzik u32 tmp; 537c6fd2807SJeff Garzik 538c6fd2807SJeff Garzik /* set FIS registers */ 539c6fd2807SJeff Garzik if (cap & HOST_CAP_64) 540c6fd2807SJeff Garzik writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); 541c6fd2807SJeff Garzik writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 542c6fd2807SJeff Garzik 543c6fd2807SJeff Garzik if (cap & HOST_CAP_64) 544c6fd2807SJeff Garzik writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI); 545c6fd2807SJeff Garzik writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 546c6fd2807SJeff Garzik 547c6fd2807SJeff Garzik /* enable FIS reception */ 548c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 549c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 550c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 551c6fd2807SJeff Garzik 552c6fd2807SJeff Garzik /* flush */ 553c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 554c6fd2807SJeff Garzik } 555c6fd2807SJeff Garzik 556c6fd2807SJeff Garzik static int ahci_stop_fis_rx(void __iomem *port_mmio) 557c6fd2807SJeff Garzik { 558c6fd2807SJeff Garzik u32 tmp; 559c6fd2807SJeff Garzik 560c6fd2807SJeff Garzik /* disable FIS reception */ 561c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 562c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 563c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 564c6fd2807SJeff Garzik 565c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 566c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 567c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 568c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 569c6fd2807SJeff Garzik return -EBUSY; 570c6fd2807SJeff Garzik 571c6fd2807SJeff Garzik return 0; 572c6fd2807SJeff Garzik } 573c6fd2807SJeff Garzik 574c6fd2807SJeff Garzik static void ahci_power_up(void __iomem *port_mmio, u32 cap) 575c6fd2807SJeff Garzik { 576c6fd2807SJeff Garzik u32 cmd; 577c6fd2807SJeff Garzik 578c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 579c6fd2807SJeff Garzik 580c6fd2807SJeff Garzik /* spin up device */ 581c6fd2807SJeff Garzik if (cap & HOST_CAP_SSS) { 582c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 583c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 584c6fd2807SJeff Garzik } 585c6fd2807SJeff Garzik 586c6fd2807SJeff Garzik /* wake up link */ 587c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 588c6fd2807SJeff Garzik } 589c6fd2807SJeff Garzik 590c6fd2807SJeff Garzik static void ahci_power_down(void __iomem *port_mmio, u32 cap) 591c6fd2807SJeff Garzik { 592c6fd2807SJeff Garzik u32 cmd, scontrol; 593c6fd2807SJeff Garzik 59407c53dacSTejun Heo if (!(cap & HOST_CAP_SSS)) 59507c53dacSTejun Heo return; 596c6fd2807SJeff Garzik 59707c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 598c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 599c6fd2807SJeff Garzik scontrol &= ~0xf; 600c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 601c6fd2807SJeff Garzik 602c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 60307c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 604c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 605c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 606c6fd2807SJeff Garzik } 607c6fd2807SJeff Garzik 608c6fd2807SJeff Garzik static void ahci_init_port(void __iomem *port_mmio, u32 cap, 609c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) 610c6fd2807SJeff Garzik { 611c6fd2807SJeff Garzik /* enable FIS reception */ 612c6fd2807SJeff Garzik ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); 613c6fd2807SJeff Garzik 614c6fd2807SJeff Garzik /* enable DMA */ 615c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 616c6fd2807SJeff Garzik } 617c6fd2807SJeff Garzik 618c6fd2807SJeff Garzik static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) 619c6fd2807SJeff Garzik { 620c6fd2807SJeff Garzik int rc; 621c6fd2807SJeff Garzik 622c6fd2807SJeff Garzik /* disable DMA */ 623c6fd2807SJeff Garzik rc = ahci_stop_engine(port_mmio); 624c6fd2807SJeff Garzik if (rc) { 625c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 626c6fd2807SJeff Garzik return rc; 627c6fd2807SJeff Garzik } 628c6fd2807SJeff Garzik 629c6fd2807SJeff Garzik /* disable FIS reception */ 630c6fd2807SJeff Garzik rc = ahci_stop_fis_rx(port_mmio); 631c6fd2807SJeff Garzik if (rc) { 632c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 633c6fd2807SJeff Garzik return rc; 634c6fd2807SJeff Garzik } 635c6fd2807SJeff Garzik 636c6fd2807SJeff Garzik return 0; 637c6fd2807SJeff Garzik } 638c6fd2807SJeff Garzik 639c6fd2807SJeff Garzik static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) 640c6fd2807SJeff Garzik { 64198fa4b60STejun Heo u32 cap_save, impl_save, tmp; 642c6fd2807SJeff Garzik 643c6fd2807SJeff Garzik cap_save = readl(mmio + HOST_CAP); 64498fa4b60STejun Heo impl_save = readl(mmio + HOST_PORTS_IMPL); 645c6fd2807SJeff Garzik 646c6fd2807SJeff Garzik /* global controller reset */ 647c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 648c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 649c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 650c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 651c6fd2807SJeff Garzik } 652c6fd2807SJeff Garzik 653c6fd2807SJeff Garzik /* reset must complete within 1 second, or 654c6fd2807SJeff Garzik * the hardware should be considered fried. 655c6fd2807SJeff Garzik */ 656c6fd2807SJeff Garzik ssleep(1); 657c6fd2807SJeff Garzik 658c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 659c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 660c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 661c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 662c6fd2807SJeff Garzik return -EIO; 663c6fd2807SJeff Garzik } 664c6fd2807SJeff Garzik 66598fa4b60STejun Heo /* turn on AHCI mode */ 666c6fd2807SJeff Garzik writel(HOST_AHCI_EN, mmio + HOST_CTL); 667c6fd2807SJeff Garzik (void) readl(mmio + HOST_CTL); /* flush */ 66898fa4b60STejun Heo 66998fa4b60STejun Heo /* These write-once registers are normally cleared on reset. 67098fa4b60STejun Heo * Restore BIOS values... which we HOPE were present before 67198fa4b60STejun Heo * reset. 67298fa4b60STejun Heo */ 67398fa4b60STejun Heo if (!impl_save) { 67498fa4b60STejun Heo impl_save = (1 << ahci_nr_ports(cap_save)) - 1; 67598fa4b60STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 67698fa4b60STejun Heo "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); 67798fa4b60STejun Heo } 678c6fd2807SJeff Garzik writel(cap_save, mmio + HOST_CAP); 67998fa4b60STejun Heo writel(impl_save, mmio + HOST_PORTS_IMPL); 680c6fd2807SJeff Garzik (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 681c6fd2807SJeff Garzik 682c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 683c6fd2807SJeff Garzik u16 tmp16; 684c6fd2807SJeff Garzik 685c6fd2807SJeff Garzik /* configure PCS */ 686c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 687c6fd2807SJeff Garzik tmp16 |= 0xf; 688c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 689c6fd2807SJeff Garzik } 690c6fd2807SJeff Garzik 691c6fd2807SJeff Garzik return 0; 692c6fd2807SJeff Garzik } 693c6fd2807SJeff Garzik 694c6fd2807SJeff Garzik static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, 695648a88beSTejun Heo int n_ports, unsigned int port_flags, 696648a88beSTejun Heo struct ahci_host_priv *hpriv) 697c6fd2807SJeff Garzik { 698c6fd2807SJeff Garzik int i, rc; 699c6fd2807SJeff Garzik u32 tmp; 700c6fd2807SJeff Garzik 701c6fd2807SJeff Garzik for (i = 0; i < n_ports; i++) { 702c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, i); 703c6fd2807SJeff Garzik const char *emsg = NULL; 704c6fd2807SJeff Garzik 705648a88beSTejun Heo if ((port_flags & AHCI_FLAG_HONOR_PI) && 706648a88beSTejun Heo !(hpriv->port_map & (1 << i))) 707c6fd2807SJeff Garzik continue; 708c6fd2807SJeff Garzik 709c6fd2807SJeff Garzik /* make sure port is not active */ 710648a88beSTejun Heo rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 711c6fd2807SJeff Garzik if (rc) 712c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 713c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 714c6fd2807SJeff Garzik 715c6fd2807SJeff Garzik /* clear SError */ 716c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 717c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 718c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 719c6fd2807SJeff Garzik 720c6fd2807SJeff Garzik /* clear port IRQ */ 721c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 722c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 723c6fd2807SJeff Garzik if (tmp) 724c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 725c6fd2807SJeff Garzik 726c6fd2807SJeff Garzik writel(1 << i, mmio + HOST_IRQ_STAT); 727c6fd2807SJeff Garzik } 728c6fd2807SJeff Garzik 729c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 730c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 731c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 732c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 733c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 734c6fd2807SJeff Garzik } 735c6fd2807SJeff Garzik 736c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 737c6fd2807SJeff Garzik { 738c6fd2807SJeff Garzik void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; 739c6fd2807SJeff Garzik struct ata_taskfile tf; 740c6fd2807SJeff Garzik u32 tmp; 741c6fd2807SJeff Garzik 742c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 743c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 744c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 745c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 746c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 747c6fd2807SJeff Garzik 748c6fd2807SJeff Garzik return ata_dev_classify(&tf); 749c6fd2807SJeff Garzik } 750c6fd2807SJeff Garzik 751c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 752c6fd2807SJeff Garzik u32 opts) 753c6fd2807SJeff Garzik { 754c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 755c6fd2807SJeff Garzik 756c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 757c6fd2807SJeff Garzik 758c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 759c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 760c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 761c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 762c6fd2807SJeff Garzik } 763c6fd2807SJeff Garzik 764c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap) 765c6fd2807SJeff Garzik { 766c6fd2807SJeff Garzik void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; 767cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 768c6fd2807SJeff Garzik u32 tmp; 769c6fd2807SJeff Garzik 770c6fd2807SJeff Garzik if (!(hpriv->cap & HOST_CAP_CLO)) 771c6fd2807SJeff Garzik return -EOPNOTSUPP; 772c6fd2807SJeff Garzik 773c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 774c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 775c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 776c6fd2807SJeff Garzik 777c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 778c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 779c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 780c6fd2807SJeff Garzik return -EIO; 781c6fd2807SJeff Garzik 782c6fd2807SJeff Garzik return 0; 783c6fd2807SJeff Garzik } 784c6fd2807SJeff Garzik 785c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class) 786c6fd2807SJeff Garzik { 787c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 788cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 789c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 790c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 791c6fd2807SJeff Garzik const char *reason = NULL; 792c6fd2807SJeff Garzik struct ata_taskfile tf; 793c6fd2807SJeff Garzik u32 tmp; 794c6fd2807SJeff Garzik u8 *fis; 795c6fd2807SJeff Garzik int rc; 796c6fd2807SJeff Garzik 797c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 798c6fd2807SJeff Garzik 799c6fd2807SJeff Garzik if (ata_port_offline(ap)) { 800c6fd2807SJeff Garzik DPRINTK("PHY reports no device\n"); 801c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 802c6fd2807SJeff Garzik return 0; 803c6fd2807SJeff Garzik } 804c6fd2807SJeff Garzik 805c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 806c6fd2807SJeff Garzik rc = ahci_stop_engine(port_mmio); 807c6fd2807SJeff Garzik if (rc) { 808c6fd2807SJeff Garzik reason = "failed to stop engine"; 809c6fd2807SJeff Garzik goto fail_restart; 810c6fd2807SJeff Garzik } 811c6fd2807SJeff Garzik 812c6fd2807SJeff Garzik /* check BUSY/DRQ, perform Command List Override if necessary */ 8131244a19cSTejun Heo if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) { 814c6fd2807SJeff Garzik rc = ahci_clo(ap); 815c6fd2807SJeff Garzik 816c6fd2807SJeff Garzik if (rc == -EOPNOTSUPP) { 817c6fd2807SJeff Garzik reason = "port busy but CLO unavailable"; 818c6fd2807SJeff Garzik goto fail_restart; 819c6fd2807SJeff Garzik } else if (rc) { 820c6fd2807SJeff Garzik reason = "port busy but CLO failed"; 821c6fd2807SJeff Garzik goto fail_restart; 822c6fd2807SJeff Garzik } 823c6fd2807SJeff Garzik } 824c6fd2807SJeff Garzik 825c6fd2807SJeff Garzik /* restart engine */ 826c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 827c6fd2807SJeff Garzik 828c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 829c6fd2807SJeff Garzik fis = pp->cmd_tbl; 830c6fd2807SJeff Garzik 831c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 832c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, 833c6fd2807SJeff Garzik cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); 834c6fd2807SJeff Garzik 835c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 836c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 837c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 838c6fd2807SJeff Garzik 839c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 840c6fd2807SJeff Garzik 841c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500); 842c6fd2807SJeff Garzik if (tmp & 0x1) { 843c6fd2807SJeff Garzik rc = -EIO; 844c6fd2807SJeff Garzik reason = "1st FIS failed"; 845c6fd2807SJeff Garzik goto fail; 846c6fd2807SJeff Garzik } 847c6fd2807SJeff Garzik 848c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 849c6fd2807SJeff Garzik msleep(1); 850c6fd2807SJeff Garzik 851c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 852c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, cmd_fis_len); 853c6fd2807SJeff Garzik 854c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 855c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 856c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 857c6fd2807SJeff Garzik 858c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 859c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 860c6fd2807SJeff Garzik 861c6fd2807SJeff Garzik /* spec mandates ">= 2ms" before checking status. 862c6fd2807SJeff Garzik * We wait 150ms, because that was the magic delay used for 863c6fd2807SJeff Garzik * ATAPI devices in Hale Landis's ATADRVR, for the period of time 864c6fd2807SJeff Garzik * between when the ATA command register is written, and then 865c6fd2807SJeff Garzik * status is checked. Because waiting for "a while" before 866c6fd2807SJeff Garzik * checking status is fine, post SRST, we perform this magic 867c6fd2807SJeff Garzik * delay here as well. 868c6fd2807SJeff Garzik */ 869c6fd2807SJeff Garzik msleep(150); 870c6fd2807SJeff Garzik 871c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 872c6fd2807SJeff Garzik if (ata_port_online(ap)) { 873c6fd2807SJeff Garzik if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { 874c6fd2807SJeff Garzik rc = -EIO; 875c6fd2807SJeff Garzik reason = "device not ready"; 876c6fd2807SJeff Garzik goto fail; 877c6fd2807SJeff Garzik } 878c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 879c6fd2807SJeff Garzik } 880c6fd2807SJeff Garzik 881c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 882c6fd2807SJeff Garzik return 0; 883c6fd2807SJeff Garzik 884c6fd2807SJeff Garzik fail_restart: 885c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 886c6fd2807SJeff Garzik fail: 887c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); 888c6fd2807SJeff Garzik return rc; 889c6fd2807SJeff Garzik } 890c6fd2807SJeff Garzik 891c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class) 892c6fd2807SJeff Garzik { 893c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 894c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 895c6fd2807SJeff Garzik struct ata_taskfile tf; 896cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 897c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 898c6fd2807SJeff Garzik int rc; 899c6fd2807SJeff Garzik 900c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 901c6fd2807SJeff Garzik 902c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 903c6fd2807SJeff Garzik 904c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 905c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 906dfd7a3dbSTejun Heo tf.command = 0x80; 907c6fd2807SJeff Garzik ata_tf_to_fis(&tf, d2h_fis, 0); 908c6fd2807SJeff Garzik 909c6fd2807SJeff Garzik rc = sata_std_hardreset(ap, class); 910c6fd2807SJeff Garzik 911c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 912c6fd2807SJeff Garzik 913c6fd2807SJeff Garzik if (rc == 0 && ata_port_online(ap)) 914c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 915c6fd2807SJeff Garzik if (*class == ATA_DEV_UNKNOWN) 916c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 917c6fd2807SJeff Garzik 918c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 919c6fd2807SJeff Garzik return rc; 920c6fd2807SJeff Garzik } 921c6fd2807SJeff Garzik 922ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) 923ad616ffbSTejun Heo { 924ad616ffbSTejun Heo void __iomem *mmio = ap->host->mmio_base; 925ad616ffbSTejun Heo void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 926ad616ffbSTejun Heo int rc; 927ad616ffbSTejun Heo 928ad616ffbSTejun Heo DPRINTK("ENTER\n"); 929ad616ffbSTejun Heo 930ad616ffbSTejun Heo ahci_stop_engine(port_mmio); 931ad616ffbSTejun Heo 932ad616ffbSTejun Heo rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); 933ad616ffbSTejun Heo 934ad616ffbSTejun Heo /* vt8251 needs SError cleared for the port to operate */ 935ad616ffbSTejun Heo ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); 936ad616ffbSTejun Heo 937ad616ffbSTejun Heo ahci_start_engine(port_mmio); 938ad616ffbSTejun Heo 939ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 940ad616ffbSTejun Heo 941ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 942ad616ffbSTejun Heo * request follow-up softreset. 943ad616ffbSTejun Heo */ 944ad616ffbSTejun Heo return rc ?: -EAGAIN; 945ad616ffbSTejun Heo } 946ad616ffbSTejun Heo 947c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class) 948c6fd2807SJeff Garzik { 949c6fd2807SJeff Garzik void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; 950c6fd2807SJeff Garzik u32 new_tmp, tmp; 951c6fd2807SJeff Garzik 952c6fd2807SJeff Garzik ata_std_postreset(ap, class); 953c6fd2807SJeff Garzik 954c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 955c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 956c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 957c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 958c6fd2807SJeff Garzik else 959c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 960c6fd2807SJeff Garzik if (new_tmp != tmp) { 961c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 962c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 963c6fd2807SJeff Garzik } 964c6fd2807SJeff Garzik } 965c6fd2807SJeff Garzik 966c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap) 967c6fd2807SJeff Garzik { 968c6fd2807SJeff Garzik void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; 969c6fd2807SJeff Garzik 970c6fd2807SJeff Garzik return readl(mmio + PORT_TFDATA) & 0xFF; 971c6fd2807SJeff Garzik } 972c6fd2807SJeff Garzik 973c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 974c6fd2807SJeff Garzik { 975c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 976c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 977c6fd2807SJeff Garzik 978c6fd2807SJeff Garzik ata_tf_from_fis(d2h_fis, tf); 979c6fd2807SJeff Garzik } 980c6fd2807SJeff Garzik 981c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 982c6fd2807SJeff Garzik { 983c6fd2807SJeff Garzik struct scatterlist *sg; 984c6fd2807SJeff Garzik struct ahci_sg *ahci_sg; 985c6fd2807SJeff Garzik unsigned int n_sg = 0; 986c6fd2807SJeff Garzik 987c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 988c6fd2807SJeff Garzik 989c6fd2807SJeff Garzik /* 990c6fd2807SJeff Garzik * Next, the S/G list. 991c6fd2807SJeff Garzik */ 992c6fd2807SJeff Garzik ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 993c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 994c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 995c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 996c6fd2807SJeff Garzik 997c6fd2807SJeff Garzik ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); 998c6fd2807SJeff Garzik ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); 999c6fd2807SJeff Garzik ahci_sg->flags_size = cpu_to_le32(sg_len - 1); 1000c6fd2807SJeff Garzik 1001c6fd2807SJeff Garzik ahci_sg++; 1002c6fd2807SJeff Garzik n_sg++; 1003c6fd2807SJeff Garzik } 1004c6fd2807SJeff Garzik 1005c6fd2807SJeff Garzik return n_sg; 1006c6fd2807SJeff Garzik } 1007c6fd2807SJeff Garzik 1008c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1009c6fd2807SJeff Garzik { 1010c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1011c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1012c6fd2807SJeff Garzik int is_atapi = is_atapi_taskfile(&qc->tf); 1013c6fd2807SJeff Garzik void *cmd_tbl; 1014c6fd2807SJeff Garzik u32 opts; 1015c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1016c6fd2807SJeff Garzik unsigned int n_elem; 1017c6fd2807SJeff Garzik 1018c6fd2807SJeff Garzik /* 1019c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1020c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1021c6fd2807SJeff Garzik */ 1022c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1023c6fd2807SJeff Garzik 1024c6fd2807SJeff Garzik ata_tf_to_fis(&qc->tf, cmd_tbl, 0); 1025c6fd2807SJeff Garzik if (is_atapi) { 1026c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1027c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1028c6fd2807SJeff Garzik } 1029c6fd2807SJeff Garzik 1030c6fd2807SJeff Garzik n_elem = 0; 1031c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1032c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1033c6fd2807SJeff Garzik 1034c6fd2807SJeff Garzik /* 1035c6fd2807SJeff Garzik * Fill in command slot information. 1036c6fd2807SJeff Garzik */ 1037c6fd2807SJeff Garzik opts = cmd_fis_len | n_elem << 16; 1038c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1039c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1040c6fd2807SJeff Garzik if (is_atapi) 1041c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1042c6fd2807SJeff Garzik 1043c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1044c6fd2807SJeff Garzik } 1045c6fd2807SJeff Garzik 1046c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1047c6fd2807SJeff Garzik { 1048c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1049c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 1050c6fd2807SJeff Garzik unsigned int err_mask = 0, action = 0; 1051c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 1052c6fd2807SJeff Garzik u32 serror; 1053c6fd2807SJeff Garzik 1054c6fd2807SJeff Garzik ata_ehi_clear_desc(ehi); 1055c6fd2807SJeff Garzik 1056c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1057c6fd2807SJeff Garzik serror = ahci_scr_read(ap, SCR_ERROR); 1058c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 1059c6fd2807SJeff Garzik 1060c6fd2807SJeff Garzik /* analyze @irq_stat */ 1061c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); 1062c6fd2807SJeff Garzik 106341669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 106441669553STejun Heo if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) 106541669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 106641669553STejun Heo 1067c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_TF_ERR) 1068c6fd2807SJeff Garzik err_mask |= AC_ERR_DEV; 1069c6fd2807SJeff Garzik 1070c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 1071c6fd2807SJeff Garzik err_mask |= AC_ERR_HOST_BUS; 1072c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1073c6fd2807SJeff Garzik } 1074c6fd2807SJeff Garzik 1075c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_IF_ERR) { 1076c6fd2807SJeff Garzik err_mask |= AC_ERR_ATA_BUS; 1077c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1078c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", interface fatal error"); 1079c6fd2807SJeff Garzik } 1080c6fd2807SJeff Garzik 1081c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 1082c6fd2807SJeff Garzik ata_ehi_hotplugged(ehi); 1083c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? 1084c6fd2807SJeff Garzik "connection status changed" : "PHY RDY changed"); 1085c6fd2807SJeff Garzik } 1086c6fd2807SJeff Garzik 1087c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1088c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1089c6fd2807SJeff Garzik 1090c6fd2807SJeff Garzik err_mask |= AC_ERR_HSM; 1091c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1092c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", 1093c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1094c6fd2807SJeff Garzik } 1095c6fd2807SJeff Garzik 1096c6fd2807SJeff Garzik /* okay, let's hand over to EH */ 1097c6fd2807SJeff Garzik ehi->serror |= serror; 1098c6fd2807SJeff Garzik ehi->action |= action; 1099c6fd2807SJeff Garzik 1100c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 1101c6fd2807SJeff Garzik if (qc) 1102c6fd2807SJeff Garzik qc->err_mask |= err_mask; 1103c6fd2807SJeff Garzik else 1104c6fd2807SJeff Garzik ehi->err_mask |= err_mask; 1105c6fd2807SJeff Garzik 1106c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1107c6fd2807SJeff Garzik ata_port_freeze(ap); 1108c6fd2807SJeff Garzik else 1109c6fd2807SJeff Garzik ata_port_abort(ap); 1110c6fd2807SJeff Garzik } 1111c6fd2807SJeff Garzik 1112c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap) 1113c6fd2807SJeff Garzik { 1114cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1115c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1116c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 11170291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 1118c6fd2807SJeff Garzik u32 status, qc_active; 11190291f95fSTejun Heo int rc, known_irq = 0; 1120c6fd2807SJeff Garzik 1121c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1122c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1123c6fd2807SJeff Garzik 1124c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1125c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1126c6fd2807SJeff Garzik return; 1127c6fd2807SJeff Garzik } 1128c6fd2807SJeff Garzik 1129c6fd2807SJeff Garzik if (ap->sactive) 1130c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1131c6fd2807SJeff Garzik else 1132c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1133c6fd2807SJeff Garzik 1134c6fd2807SJeff Garzik rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1135c6fd2807SJeff Garzik if (rc > 0) 1136c6fd2807SJeff Garzik return; 1137c6fd2807SJeff Garzik if (rc < 0) { 1138c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1139c6fd2807SJeff Garzik ehi->action |= ATA_EH_SOFTRESET; 1140c6fd2807SJeff Garzik ata_port_freeze(ap); 1141c6fd2807SJeff Garzik return; 1142c6fd2807SJeff Garzik } 1143c6fd2807SJeff Garzik 1144c6fd2807SJeff Garzik /* hmmm... a spurious interupt */ 1145c6fd2807SJeff Garzik 11460291f95fSTejun Heo /* if !NCQ, ignore. No modern ATA device has broken HSM 11470291f95fSTejun Heo * implementation for non-NCQ commands. 11480291f95fSTejun Heo */ 11490291f95fSTejun Heo if (!ap->sactive) 1150c6fd2807SJeff Garzik return; 1151c6fd2807SJeff Garzik 11520291f95fSTejun Heo if (status & PORT_IRQ_D2H_REG_FIS) { 11530291f95fSTejun Heo if (!pp->ncq_saw_d2h) 11540291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 11550291f95fSTejun Heo "D2H reg with I during NCQ, " 11560291f95fSTejun Heo "this message won't be printed again\n"); 11570291f95fSTejun Heo pp->ncq_saw_d2h = 1; 11580291f95fSTejun Heo known_irq = 1; 11590291f95fSTejun Heo } 1160c6fd2807SJeff Garzik 11610291f95fSTejun Heo if (status & PORT_IRQ_DMAS_FIS) { 11620291f95fSTejun Heo if (!pp->ncq_saw_dmas) 11630291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 11640291f95fSTejun Heo "DMAS FIS during NCQ, " 11650291f95fSTejun Heo "this message won't be printed again\n"); 11660291f95fSTejun Heo pp->ncq_saw_dmas = 1; 11670291f95fSTejun Heo known_irq = 1; 11680291f95fSTejun Heo } 11690291f95fSTejun Heo 11700291f95fSTejun Heo if (status & PORT_IRQ_SDB_FIS && 11710291f95fSTejun Heo pp->ncq_saw_spurious_sdb_cnt < 10) { 11720291f95fSTejun Heo /* SDB FIS containing spurious completions might be 11730291f95fSTejun Heo * dangerous, we need to know more about them. Print 11740291f95fSTejun Heo * more of it. 11750291f95fSTejun Heo */ 117604d4f7a1SAl Viro const __le32 *f = pp->rx_fis + RX_FIS_SDB; 11770291f95fSTejun Heo 11780291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " 11790291f95fSTejun Heo "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", 11800291f95fSTejun Heo readl(port_mmio + PORT_CMD_ISSUE), 11816096b63eSTejun Heo readl(port_mmio + PORT_SCR_ACT), 11826096b63eSTejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1]), 11830291f95fSTejun Heo pp->ncq_saw_spurious_sdb_cnt < 10 ? 11840291f95fSTejun Heo "" : ", shutting up"); 11850291f95fSTejun Heo 11860291f95fSTejun Heo pp->ncq_saw_spurious_sdb_cnt++; 11870291f95fSTejun Heo known_irq = 1; 11880291f95fSTejun Heo } 11890291f95fSTejun Heo 11900291f95fSTejun Heo if (!known_irq) 1191c6fd2807SJeff Garzik ata_port_printk(ap, KERN_INFO, "spurious interrupt " 11920291f95fSTejun Heo "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", 1193c6fd2807SJeff Garzik status, ap->active_tag, ap->sactive); 1194c6fd2807SJeff Garzik } 1195c6fd2807SJeff Garzik 1196c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap) 1197c6fd2807SJeff Garzik { 1198c6fd2807SJeff Garzik /* TODO */ 1199c6fd2807SJeff Garzik } 1200c6fd2807SJeff Garzik 12017d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1202c6fd2807SJeff Garzik { 1203cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1204c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1205c6fd2807SJeff Garzik unsigned int i, handled = 0; 1206c6fd2807SJeff Garzik void __iomem *mmio; 1207c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1208c6fd2807SJeff Garzik 1209c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1210c6fd2807SJeff Garzik 1211cca3974eSJeff Garzik hpriv = host->private_data; 1212cca3974eSJeff Garzik mmio = host->mmio_base; 1213c6fd2807SJeff Garzik 1214c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1215c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1216c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1217c6fd2807SJeff Garzik if (!irq_stat) 1218c6fd2807SJeff Garzik return IRQ_NONE; 1219c6fd2807SJeff Garzik 1220cca3974eSJeff Garzik spin_lock(&host->lock); 1221c6fd2807SJeff Garzik 1222cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1223c6fd2807SJeff Garzik struct ata_port *ap; 1224c6fd2807SJeff Garzik 1225c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1226c6fd2807SJeff Garzik continue; 1227c6fd2807SJeff Garzik 1228cca3974eSJeff Garzik ap = host->ports[i]; 1229c6fd2807SJeff Garzik if (ap) { 1230c6fd2807SJeff Garzik ahci_host_intr(ap); 1231c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1232c6fd2807SJeff Garzik } else { 1233c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1234c6fd2807SJeff Garzik if (ata_ratelimit()) 1235cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1236c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1237c6fd2807SJeff Garzik } 1238c6fd2807SJeff Garzik 1239c6fd2807SJeff Garzik irq_ack |= (1 << i); 1240c6fd2807SJeff Garzik } 1241c6fd2807SJeff Garzik 1242c6fd2807SJeff Garzik if (irq_ack) { 1243c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1244c6fd2807SJeff Garzik handled = 1; 1245c6fd2807SJeff Garzik } 1246c6fd2807SJeff Garzik 1247cca3974eSJeff Garzik spin_unlock(&host->lock); 1248c6fd2807SJeff Garzik 1249c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1250c6fd2807SJeff Garzik 1251c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1252c6fd2807SJeff Garzik } 1253c6fd2807SJeff Garzik 1254c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1255c6fd2807SJeff Garzik { 1256c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1257c6fd2807SJeff Garzik void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; 1258c6fd2807SJeff Garzik 1259c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1260c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1261c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1262c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1263c6fd2807SJeff Garzik 1264c6fd2807SJeff Garzik return 0; 1265c6fd2807SJeff Garzik } 1266c6fd2807SJeff Garzik 1267c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1268c6fd2807SJeff Garzik { 1269cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1270c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1271c6fd2807SJeff Garzik 1272c6fd2807SJeff Garzik /* turn IRQ off */ 1273c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1274c6fd2807SJeff Garzik } 1275c6fd2807SJeff Garzik 1276c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1277c6fd2807SJeff Garzik { 1278cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1279c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1280c6fd2807SJeff Garzik u32 tmp; 1281c6fd2807SJeff Garzik 1282c6fd2807SJeff Garzik /* clear IRQ */ 1283c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1284c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1285a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1286c6fd2807SJeff Garzik 1287c6fd2807SJeff Garzik /* turn IRQ back on */ 1288c6fd2807SJeff Garzik writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); 1289c6fd2807SJeff Garzik } 1290c6fd2807SJeff Garzik 1291c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1292c6fd2807SJeff Garzik { 1293cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1294c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1295c6fd2807SJeff Garzik 1296c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1297c6fd2807SJeff Garzik /* restart engine */ 1298c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 1299c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 1300c6fd2807SJeff Garzik } 1301c6fd2807SJeff Garzik 1302c6fd2807SJeff Garzik /* perform recovery */ 13034aeb0e32STejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, 1304c6fd2807SJeff Garzik ahci_postreset); 1305c6fd2807SJeff Garzik } 1306c6fd2807SJeff Garzik 1307ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap) 1308ad616ffbSTejun Heo { 1309ad616ffbSTejun Heo void __iomem *mmio = ap->host->mmio_base; 1310ad616ffbSTejun Heo void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1311ad616ffbSTejun Heo 1312ad616ffbSTejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1313ad616ffbSTejun Heo /* restart engine */ 1314ad616ffbSTejun Heo ahci_stop_engine(port_mmio); 1315ad616ffbSTejun Heo ahci_start_engine(port_mmio); 1316ad616ffbSTejun Heo } 1317ad616ffbSTejun Heo 1318ad616ffbSTejun Heo /* perform recovery */ 1319ad616ffbSTejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, 1320ad616ffbSTejun Heo ahci_postreset); 1321ad616ffbSTejun Heo } 1322ad616ffbSTejun Heo 1323c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1324c6fd2807SJeff Garzik { 1325c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1326cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1327c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1328c6fd2807SJeff Garzik 1329c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_FAILED) 1330c6fd2807SJeff Garzik qc->err_mask |= AC_ERR_OTHER; 1331c6fd2807SJeff Garzik 1332c6fd2807SJeff Garzik if (qc->err_mask) { 1333c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1334c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 1335c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 1336c6fd2807SJeff Garzik } 1337c6fd2807SJeff Garzik } 1338c6fd2807SJeff Garzik 1339c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1340c6fd2807SJeff Garzik { 1341cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1342c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1343cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1344c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1345c6fd2807SJeff Garzik const char *emsg = NULL; 1346c6fd2807SJeff Garzik int rc; 1347c6fd2807SJeff Garzik 1348c6fd2807SJeff Garzik rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 13498e16f941STejun Heo if (rc == 0) 13508e16f941STejun Heo ahci_power_down(port_mmio, hpriv->cap); 13518e16f941STejun Heo else { 1352c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1353c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, 1354c6fd2807SJeff Garzik pp->cmd_slot_dma, pp->rx_fis_dma); 1355c6fd2807SJeff Garzik } 1356c6fd2807SJeff Garzik 1357c6fd2807SJeff Garzik return rc; 1358c6fd2807SJeff Garzik } 1359c6fd2807SJeff Garzik 1360c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap) 1361c6fd2807SJeff Garzik { 1362c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1363cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1364cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1365c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1366c6fd2807SJeff Garzik 13678e16f941STejun Heo ahci_power_up(port_mmio, hpriv->cap); 1368c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); 1369c6fd2807SJeff Garzik 1370c6fd2807SJeff Garzik return 0; 1371c6fd2807SJeff Garzik } 1372c6fd2807SJeff Garzik 1373c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1374c6fd2807SJeff Garzik { 1375cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1376cca3974eSJeff Garzik void __iomem *mmio = host->mmio_base; 1377c6fd2807SJeff Garzik u32 ctl; 1378c6fd2807SJeff Garzik 1379c6fd2807SJeff Garzik if (mesg.event == PM_EVENT_SUSPEND) { 1380c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1381c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1382c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1383c6fd2807SJeff Garzik */ 1384c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1385c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1386c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1387c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1388c6fd2807SJeff Garzik } 1389c6fd2807SJeff Garzik 1390c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1391c6fd2807SJeff Garzik } 1392c6fd2807SJeff Garzik 1393c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1394c6fd2807SJeff Garzik { 1395cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1396cca3974eSJeff Garzik struct ahci_host_priv *hpriv = host->private_data; 1397cca3974eSJeff Garzik void __iomem *mmio = host->mmio_base; 1398c6fd2807SJeff Garzik int rc; 1399c6fd2807SJeff Garzik 1400c6fd2807SJeff Garzik ata_pci_device_do_resume(pdev); 1401c6fd2807SJeff Garzik 1402c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 1403c6fd2807SJeff Garzik rc = ahci_reset_controller(mmio, pdev); 1404c6fd2807SJeff Garzik if (rc) 1405c6fd2807SJeff Garzik return rc; 1406c6fd2807SJeff Garzik 1407648a88beSTejun Heo ahci_init_controller(mmio, pdev, host->n_ports, 1408648a88beSTejun Heo host->ports[0]->flags, hpriv); 1409c6fd2807SJeff Garzik } 1410c6fd2807SJeff Garzik 1411cca3974eSJeff Garzik ata_host_resume(host); 1412c6fd2807SJeff Garzik 1413c6fd2807SJeff Garzik return 0; 1414c6fd2807SJeff Garzik } 1415c6fd2807SJeff Garzik 1416c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1417c6fd2807SJeff Garzik { 1418cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1419cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1420c6fd2807SJeff Garzik struct ahci_port_priv *pp; 1421cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1422c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1423c6fd2807SJeff Garzik void *mem; 1424c6fd2807SJeff Garzik dma_addr_t mem_dma; 1425c6fd2807SJeff Garzik int rc; 1426c6fd2807SJeff Garzik 1427c6fd2807SJeff Garzik pp = kmalloc(sizeof(*pp), GFP_KERNEL); 1428c6fd2807SJeff Garzik if (!pp) 1429c6fd2807SJeff Garzik return -ENOMEM; 1430c6fd2807SJeff Garzik memset(pp, 0, sizeof(*pp)); 1431c6fd2807SJeff Garzik 1432c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 1433c6fd2807SJeff Garzik if (rc) { 1434c6fd2807SJeff Garzik kfree(pp); 1435c6fd2807SJeff Garzik return rc; 1436c6fd2807SJeff Garzik } 1437c6fd2807SJeff Garzik 1438c6fd2807SJeff Garzik mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); 1439c6fd2807SJeff Garzik if (!mem) { 1440c6fd2807SJeff Garzik ata_pad_free(ap, dev); 1441c6fd2807SJeff Garzik kfree(pp); 1442c6fd2807SJeff Garzik return -ENOMEM; 1443c6fd2807SJeff Garzik } 1444c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1445c6fd2807SJeff Garzik 1446c6fd2807SJeff Garzik /* 1447c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1448c6fd2807SJeff Garzik * 32 bytes each in size 1449c6fd2807SJeff Garzik */ 1450c6fd2807SJeff Garzik pp->cmd_slot = mem; 1451c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 1452c6fd2807SJeff Garzik 1453c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 1454c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 1455c6fd2807SJeff Garzik 1456c6fd2807SJeff Garzik /* 1457c6fd2807SJeff Garzik * Second item: Received-FIS area 1458c6fd2807SJeff Garzik */ 1459c6fd2807SJeff Garzik pp->rx_fis = mem; 1460c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 1461c6fd2807SJeff Garzik 1462c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 1463c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 1464c6fd2807SJeff Garzik 1465c6fd2807SJeff Garzik /* 1466c6fd2807SJeff Garzik * Third item: data area for storing a single command 1467c6fd2807SJeff Garzik * and its scatter-gather table 1468c6fd2807SJeff Garzik */ 1469c6fd2807SJeff Garzik pp->cmd_tbl = mem; 1470c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 1471c6fd2807SJeff Garzik 1472c6fd2807SJeff Garzik ap->private_data = pp; 1473c6fd2807SJeff Garzik 14748e16f941STejun Heo /* power up port */ 14758e16f941STejun Heo ahci_power_up(port_mmio, hpriv->cap); 14768e16f941STejun Heo 1477c6fd2807SJeff Garzik /* initialize port */ 1478c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); 1479c6fd2807SJeff Garzik 1480c6fd2807SJeff Garzik return 0; 1481c6fd2807SJeff Garzik } 1482c6fd2807SJeff Garzik 1483c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 1484c6fd2807SJeff Garzik { 1485cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1486cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1487c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1488cca3974eSJeff Garzik void __iomem *mmio = ap->host->mmio_base; 1489c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1490c6fd2807SJeff Garzik const char *emsg = NULL; 1491c6fd2807SJeff Garzik int rc; 1492c6fd2807SJeff Garzik 1493c6fd2807SJeff Garzik /* de-initialize port */ 1494c6fd2807SJeff Garzik rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 1495c6fd2807SJeff Garzik if (rc) 1496c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 1497c6fd2807SJeff Garzik 1498c6fd2807SJeff Garzik ap->private_data = NULL; 1499c6fd2807SJeff Garzik dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, 1500c6fd2807SJeff Garzik pp->cmd_slot, pp->cmd_slot_dma); 1501c6fd2807SJeff Garzik ata_pad_free(ap, dev); 1502c6fd2807SJeff Garzik kfree(pp); 1503c6fd2807SJeff Garzik } 1504c6fd2807SJeff Garzik 1505c6fd2807SJeff Garzik static void ahci_setup_port(struct ata_ioports *port, unsigned long base, 1506c6fd2807SJeff Garzik unsigned int port_idx) 1507c6fd2807SJeff Garzik { 1508c6fd2807SJeff Garzik VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); 1509c6fd2807SJeff Garzik base = ahci_port_base_ul(base, port_idx); 1510c6fd2807SJeff Garzik VPRINTK("base now==0x%lx\n", base); 1511c6fd2807SJeff Garzik 1512c6fd2807SJeff Garzik port->cmd_addr = base; 1513c6fd2807SJeff Garzik port->scr_addr = base + PORT_SCR; 1514c6fd2807SJeff Garzik 1515c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1516c6fd2807SJeff Garzik } 1517c6fd2807SJeff Garzik 1518c6fd2807SJeff Garzik static int ahci_host_init(struct ata_probe_ent *probe_ent) 1519c6fd2807SJeff Garzik { 1520c6fd2807SJeff Garzik struct ahci_host_priv *hpriv = probe_ent->private_data; 1521c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(probe_ent->dev); 1522c6fd2807SJeff Garzik void __iomem *mmio = probe_ent->mmio_base; 1523648a88beSTejun Heo unsigned int i, cap_n_ports, using_dac; 1524c6fd2807SJeff Garzik int rc; 1525c6fd2807SJeff Garzik 1526c6fd2807SJeff Garzik rc = ahci_reset_controller(mmio, pdev); 1527c6fd2807SJeff Garzik if (rc) 1528c6fd2807SJeff Garzik return rc; 1529c6fd2807SJeff Garzik 1530c6fd2807SJeff Garzik hpriv->cap = readl(mmio + HOST_CAP); 1531c6fd2807SJeff Garzik hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); 1532648a88beSTejun Heo cap_n_ports = ahci_nr_ports(hpriv->cap); 1533c6fd2807SJeff Garzik 1534c6fd2807SJeff Garzik VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", 1535648a88beSTejun Heo hpriv->cap, hpriv->port_map, cap_n_ports); 1536648a88beSTejun Heo 1537648a88beSTejun Heo if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { 1538648a88beSTejun Heo unsigned int n_ports = cap_n_ports; 1539648a88beSTejun Heo u32 port_map = hpriv->port_map; 1540648a88beSTejun Heo int max_port = 0; 1541648a88beSTejun Heo 1542648a88beSTejun Heo for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { 1543648a88beSTejun Heo if (port_map & (1 << i)) { 1544648a88beSTejun Heo n_ports--; 1545648a88beSTejun Heo port_map &= ~(1 << i); 1546648a88beSTejun Heo max_port = i; 1547648a88beSTejun Heo } else 1548648a88beSTejun Heo probe_ent->dummy_port_mask |= 1 << i; 1549648a88beSTejun Heo } 1550648a88beSTejun Heo 1551648a88beSTejun Heo if (n_ports || port_map) 1552648a88beSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 1553648a88beSTejun Heo "nr_ports (%u) and implemented port map " 1554648a88beSTejun Heo "(0x%x) don't match\n", 1555648a88beSTejun Heo cap_n_ports, hpriv->port_map); 1556648a88beSTejun Heo 1557648a88beSTejun Heo probe_ent->n_ports = max_port + 1; 1558648a88beSTejun Heo } else 1559648a88beSTejun Heo probe_ent->n_ports = cap_n_ports; 1560c6fd2807SJeff Garzik 1561c6fd2807SJeff Garzik using_dac = hpriv->cap & HOST_CAP_64; 1562c6fd2807SJeff Garzik if (using_dac && 1563c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 1564c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 1565c6fd2807SJeff Garzik if (rc) { 1566c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1567c6fd2807SJeff Garzik if (rc) { 1568c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1569c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 1570c6fd2807SJeff Garzik return rc; 1571c6fd2807SJeff Garzik } 1572c6fd2807SJeff Garzik } 1573c6fd2807SJeff Garzik } else { 1574c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 1575c6fd2807SJeff Garzik if (rc) { 1576c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1577c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 1578c6fd2807SJeff Garzik return rc; 1579c6fd2807SJeff Garzik } 1580c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1581c6fd2807SJeff Garzik if (rc) { 1582c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1583c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 1584c6fd2807SJeff Garzik return rc; 1585c6fd2807SJeff Garzik } 1586c6fd2807SJeff Garzik } 1587c6fd2807SJeff Garzik 1588c6fd2807SJeff Garzik for (i = 0; i < probe_ent->n_ports; i++) 1589c6fd2807SJeff Garzik ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); 1590c6fd2807SJeff Garzik 1591648a88beSTejun Heo ahci_init_controller(mmio, pdev, probe_ent->n_ports, 1592648a88beSTejun Heo probe_ent->port_flags, hpriv); 1593c6fd2807SJeff Garzik 1594c6fd2807SJeff Garzik pci_set_master(pdev); 1595c6fd2807SJeff Garzik 1596c6fd2807SJeff Garzik return 0; 1597c6fd2807SJeff Garzik } 1598c6fd2807SJeff Garzik 1599c6fd2807SJeff Garzik static void ahci_print_info(struct ata_probe_ent *probe_ent) 1600c6fd2807SJeff Garzik { 1601c6fd2807SJeff Garzik struct ahci_host_priv *hpriv = probe_ent->private_data; 1602c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(probe_ent->dev); 1603c6fd2807SJeff Garzik void __iomem *mmio = probe_ent->mmio_base; 1604c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 1605c6fd2807SJeff Garzik const char *speed_s; 1606c6fd2807SJeff Garzik u16 cc; 1607c6fd2807SJeff Garzik const char *scc_s; 1608c6fd2807SJeff Garzik 1609c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 1610c6fd2807SJeff Garzik cap = hpriv->cap; 1611c6fd2807SJeff Garzik impl = hpriv->port_map; 1612c6fd2807SJeff Garzik 1613c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 1614c6fd2807SJeff Garzik if (speed == 1) 1615c6fd2807SJeff Garzik speed_s = "1.5"; 1616c6fd2807SJeff Garzik else if (speed == 2) 1617c6fd2807SJeff Garzik speed_s = "3"; 1618c6fd2807SJeff Garzik else 1619c6fd2807SJeff Garzik speed_s = "?"; 1620c6fd2807SJeff Garzik 1621c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 1622*c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 1623c6fd2807SJeff Garzik scc_s = "IDE"; 1624*c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 1625c6fd2807SJeff Garzik scc_s = "SATA"; 1626*c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 1627c6fd2807SJeff Garzik scc_s = "RAID"; 1628c6fd2807SJeff Garzik else 1629c6fd2807SJeff Garzik scc_s = "unknown"; 1630c6fd2807SJeff Garzik 1631c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1632c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 1633c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 1634c6fd2807SJeff Garzik , 1635c6fd2807SJeff Garzik 1636c6fd2807SJeff Garzik (vers >> 24) & 0xff, 1637c6fd2807SJeff Garzik (vers >> 16) & 0xff, 1638c6fd2807SJeff Garzik (vers >> 8) & 0xff, 1639c6fd2807SJeff Garzik vers & 0xff, 1640c6fd2807SJeff Garzik 1641c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 1642c6fd2807SJeff Garzik (cap & 0x1f) + 1, 1643c6fd2807SJeff Garzik speed_s, 1644c6fd2807SJeff Garzik impl, 1645c6fd2807SJeff Garzik scc_s); 1646c6fd2807SJeff Garzik 1647c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1648c6fd2807SJeff Garzik "flags: " 1649c6fd2807SJeff Garzik "%s%s%s%s%s%s" 1650c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 1651c6fd2807SJeff Garzik , 1652c6fd2807SJeff Garzik 1653c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 1654c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 1655c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 1656c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 1657c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 1658c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 1659c6fd2807SJeff Garzik 1660c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 1661c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 1662c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 1663c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 1664c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 1665c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 1666c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 1667c6fd2807SJeff Garzik ); 1668c6fd2807SJeff Garzik } 1669c6fd2807SJeff Garzik 1670c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 1671c6fd2807SJeff Garzik { 1672c6fd2807SJeff Garzik static int printed_version; 1673c6fd2807SJeff Garzik struct ata_probe_ent *probe_ent = NULL; 1674c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1675c6fd2807SJeff Garzik unsigned long base; 1676c6fd2807SJeff Garzik void __iomem *mmio_base; 1677c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 1678c6fd2807SJeff Garzik int have_msi, pci_dev_busy = 0; 1679c6fd2807SJeff Garzik int rc; 1680c6fd2807SJeff Garzik 1681c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1682c6fd2807SJeff Garzik 1683c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 1684c6fd2807SJeff Garzik 1685c6fd2807SJeff Garzik if (!printed_version++) 1686c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 1687c6fd2807SJeff Garzik 1688c6fd2807SJeff Garzik /* JMicron-specific fixup: make sure we're in AHCI mode */ 1689c6fd2807SJeff Garzik /* This is protected from races with ata_jmicron by the pci probe 1690c6fd2807SJeff Garzik locking */ 1691c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_JMICRON) { 1692c6fd2807SJeff Garzik /* AHCI enable, AHCI on function 0 */ 1693c6fd2807SJeff Garzik pci_write_config_byte(pdev, 0x41, 0xa1); 1694c6fd2807SJeff Garzik /* Function 1 is the PATA controller */ 1695c6fd2807SJeff Garzik if (PCI_FUNC(pdev->devfn)) 1696c6fd2807SJeff Garzik return -ENODEV; 1697c6fd2807SJeff Garzik } 1698c6fd2807SJeff Garzik 1699c6fd2807SJeff Garzik rc = pci_enable_device(pdev); 1700c6fd2807SJeff Garzik if (rc) 1701c6fd2807SJeff Garzik return rc; 1702c6fd2807SJeff Garzik 1703c6fd2807SJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 1704c6fd2807SJeff Garzik if (rc) { 1705c6fd2807SJeff Garzik pci_dev_busy = 1; 1706c6fd2807SJeff Garzik goto err_out; 1707c6fd2807SJeff Garzik } 1708c6fd2807SJeff Garzik 1709c6fd2807SJeff Garzik if (pci_enable_msi(pdev) == 0) 1710c6fd2807SJeff Garzik have_msi = 1; 1711c6fd2807SJeff Garzik else { 1712c6fd2807SJeff Garzik pci_intx(pdev, 1); 1713c6fd2807SJeff Garzik have_msi = 0; 1714c6fd2807SJeff Garzik } 1715c6fd2807SJeff Garzik 1716c6fd2807SJeff Garzik probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); 1717c6fd2807SJeff Garzik if (probe_ent == NULL) { 1718c6fd2807SJeff Garzik rc = -ENOMEM; 1719c6fd2807SJeff Garzik goto err_out_msi; 1720c6fd2807SJeff Garzik } 1721c6fd2807SJeff Garzik 1722c6fd2807SJeff Garzik memset(probe_ent, 0, sizeof(*probe_ent)); 1723c6fd2807SJeff Garzik probe_ent->dev = pci_dev_to_dev(pdev); 1724c6fd2807SJeff Garzik INIT_LIST_HEAD(&probe_ent->node); 1725c6fd2807SJeff Garzik 1726c6fd2807SJeff Garzik mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0); 1727c6fd2807SJeff Garzik if (mmio_base == NULL) { 1728c6fd2807SJeff Garzik rc = -ENOMEM; 1729c6fd2807SJeff Garzik goto err_out_free_ent; 1730c6fd2807SJeff Garzik } 1731c6fd2807SJeff Garzik base = (unsigned long) mmio_base; 1732c6fd2807SJeff Garzik 1733c6fd2807SJeff Garzik hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); 1734c6fd2807SJeff Garzik if (!hpriv) { 1735c6fd2807SJeff Garzik rc = -ENOMEM; 1736c6fd2807SJeff Garzik goto err_out_iounmap; 1737c6fd2807SJeff Garzik } 1738c6fd2807SJeff Garzik memset(hpriv, 0, sizeof(*hpriv)); 1739c6fd2807SJeff Garzik 1740c6fd2807SJeff Garzik probe_ent->sht = ahci_port_info[board_idx].sht; 1741cca3974eSJeff Garzik probe_ent->port_flags = ahci_port_info[board_idx].flags; 1742c6fd2807SJeff Garzik probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask; 1743c6fd2807SJeff Garzik probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask; 1744c6fd2807SJeff Garzik probe_ent->port_ops = ahci_port_info[board_idx].port_ops; 1745c6fd2807SJeff Garzik 1746c6fd2807SJeff Garzik probe_ent->irq = pdev->irq; 1747c6fd2807SJeff Garzik probe_ent->irq_flags = IRQF_SHARED; 1748c6fd2807SJeff Garzik probe_ent->mmio_base = mmio_base; 1749c6fd2807SJeff Garzik probe_ent->private_data = hpriv; 1750c6fd2807SJeff Garzik 1751c6fd2807SJeff Garzik if (have_msi) 1752c6fd2807SJeff Garzik hpriv->flags |= AHCI_FLAG_MSI; 1753c6fd2807SJeff Garzik 1754c6fd2807SJeff Garzik /* initialize adapter */ 1755c6fd2807SJeff Garzik rc = ahci_host_init(probe_ent); 1756c6fd2807SJeff Garzik if (rc) 1757c6fd2807SJeff Garzik goto err_out_hpriv; 1758c6fd2807SJeff Garzik 1759cca3974eSJeff Garzik if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) && 1760c6fd2807SJeff Garzik (hpriv->cap & HOST_CAP_NCQ)) 1761cca3974eSJeff Garzik probe_ent->port_flags |= ATA_FLAG_NCQ; 1762c6fd2807SJeff Garzik 1763c6fd2807SJeff Garzik ahci_print_info(probe_ent); 1764c6fd2807SJeff Garzik 1765c6fd2807SJeff Garzik /* FIXME: check ata_device_add return value */ 1766c6fd2807SJeff Garzik ata_device_add(probe_ent); 1767c6fd2807SJeff Garzik kfree(probe_ent); 1768c6fd2807SJeff Garzik 1769c6fd2807SJeff Garzik return 0; 1770c6fd2807SJeff Garzik 1771c6fd2807SJeff Garzik err_out_hpriv: 1772c6fd2807SJeff Garzik kfree(hpriv); 1773c6fd2807SJeff Garzik err_out_iounmap: 1774c6fd2807SJeff Garzik pci_iounmap(pdev, mmio_base); 1775c6fd2807SJeff Garzik err_out_free_ent: 1776c6fd2807SJeff Garzik kfree(probe_ent); 1777c6fd2807SJeff Garzik err_out_msi: 1778c6fd2807SJeff Garzik if (have_msi) 1779c6fd2807SJeff Garzik pci_disable_msi(pdev); 1780c6fd2807SJeff Garzik else 1781c6fd2807SJeff Garzik pci_intx(pdev, 0); 1782c6fd2807SJeff Garzik pci_release_regions(pdev); 1783c6fd2807SJeff Garzik err_out: 1784c6fd2807SJeff Garzik if (!pci_dev_busy) 1785c6fd2807SJeff Garzik pci_disable_device(pdev); 1786c6fd2807SJeff Garzik return rc; 1787c6fd2807SJeff Garzik } 1788c6fd2807SJeff Garzik 1789c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev) 1790c6fd2807SJeff Garzik { 1791c6fd2807SJeff Garzik struct device *dev = pci_dev_to_dev(pdev); 1792cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(dev); 1793cca3974eSJeff Garzik struct ahci_host_priv *hpriv = host->private_data; 1794c6fd2807SJeff Garzik unsigned int i; 1795c6fd2807SJeff Garzik int have_msi; 1796c6fd2807SJeff Garzik 1797cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) 1798cca3974eSJeff Garzik ata_port_detach(host->ports[i]); 1799c6fd2807SJeff Garzik 1800c6fd2807SJeff Garzik have_msi = hpriv->flags & AHCI_FLAG_MSI; 1801cca3974eSJeff Garzik free_irq(host->irq, host); 1802c6fd2807SJeff Garzik 1803cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1804cca3974eSJeff Garzik struct ata_port *ap = host->ports[i]; 1805c6fd2807SJeff Garzik 1806cca3974eSJeff Garzik ata_scsi_release(ap->scsi_host); 1807cca3974eSJeff Garzik scsi_host_put(ap->scsi_host); 1808c6fd2807SJeff Garzik } 1809c6fd2807SJeff Garzik 1810c6fd2807SJeff Garzik kfree(hpriv); 1811cca3974eSJeff Garzik pci_iounmap(pdev, host->mmio_base); 1812cca3974eSJeff Garzik kfree(host); 1813c6fd2807SJeff Garzik 1814c6fd2807SJeff Garzik if (have_msi) 1815c6fd2807SJeff Garzik pci_disable_msi(pdev); 1816c6fd2807SJeff Garzik else 1817c6fd2807SJeff Garzik pci_intx(pdev, 0); 1818c6fd2807SJeff Garzik pci_release_regions(pdev); 1819c6fd2807SJeff Garzik pci_disable_device(pdev); 1820c6fd2807SJeff Garzik dev_set_drvdata(dev, NULL); 1821c6fd2807SJeff Garzik } 1822c6fd2807SJeff Garzik 1823c6fd2807SJeff Garzik static int __init ahci_init(void) 1824c6fd2807SJeff Garzik { 1825c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 1826c6fd2807SJeff Garzik } 1827c6fd2807SJeff Garzik 1828c6fd2807SJeff Garzik static void __exit ahci_exit(void) 1829c6fd2807SJeff Garzik { 1830c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 1831c6fd2807SJeff Garzik } 1832c6fd2807SJeff Garzik 1833c6fd2807SJeff Garzik 1834c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 1835c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 1836c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 1837c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 1838c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 1839c6fd2807SJeff Garzik 1840c6fd2807SJeff Garzik module_init(ahci_init); 1841c6fd2807SJeff Garzik module_exit(ahci_exit); 1842