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/dma-mapping.h> 43c6fd2807SJeff Garzik #include <linux/device.h> 44c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 45c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h> 46c6fd2807SJeff Garzik #include <linux/libata.h> 47c6fd2807SJeff Garzik 48c6fd2807SJeff Garzik #define DRV_NAME "ahci" 49cb48cab7SJeff Garzik #define DRV_VERSION "2.1" 50c6fd2807SJeff Garzik 51c6fd2807SJeff Garzik 52c6fd2807SJeff Garzik enum { 53c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 54648a88beSTejun Heo AHCI_MAX_PORTS = 32, 55c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 56c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 57c6fd2807SJeff Garzik AHCI_USE_CLUSTERING = 0, 58c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 59c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 60c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 61c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 62c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 63c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 64c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 65c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 66c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 67c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 68c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 69c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 70c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 71c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 72c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 73c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 74c6fd2807SJeff Garzik 75c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 760291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 77c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 78c6fd2807SJeff Garzik 79c6fd2807SJeff Garzik board_ahci = 0, 80648a88beSTejun Heo board_ahci_pi = 1, 81648a88beSTejun Heo board_ahci_vt8251 = 2, 82648a88beSTejun Heo board_ahci_ign_iferr = 3, 83c6fd2807SJeff Garzik 84c6fd2807SJeff Garzik /* global controller registers */ 85c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 86c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 87c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 88c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 89c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 90c6fd2807SJeff Garzik 91c6fd2807SJeff Garzik /* HOST_CTL bits */ 92c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 93c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 94c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 95c6fd2807SJeff Garzik 96c6fd2807SJeff Garzik /* HOST_CAP bits */ 97c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 98c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 99c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 100c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 101c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 102c6fd2807SJeff Garzik 103c6fd2807SJeff Garzik /* registers for each SATA port */ 104c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 105c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 106c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 107c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 108c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 109c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 110c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 111c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 112c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 113c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 114c6fd2807SJeff Garzik PORT_SCR = 0x28, /* SATA phy register block */ 115c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 116c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 117c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 118c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 119c6fd2807SJeff Garzik 120c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 121c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 122c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 123c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 124c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 125c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 126c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 127c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 128c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 129c6fd2807SJeff Garzik 130c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 131c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 132c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 133c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 134c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 135c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 136c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 137c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 138c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 139c6fd2807SJeff Garzik 140c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 141c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 142c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 143c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 144c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS, 145c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 146c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 147c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 148c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 149c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 150c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 151c6fd2807SJeff Garzik 152c6fd2807SJeff Garzik /* PORT_CMD bits */ 153c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 154c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 155c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 156c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 157c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 158c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 159c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 160c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 161c6fd2807SJeff Garzik 162c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 163c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 164c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 165c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 166c6fd2807SJeff Garzik 167c6fd2807SJeff Garzik /* ap->flags bits */ 1684aeb0e32STejun Heo AHCI_FLAG_NO_NCQ = (1 << 24), 1694aeb0e32STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ 170648a88beSTejun Heo AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ 171c6fd2807SJeff Garzik }; 172c6fd2807SJeff Garzik 173c6fd2807SJeff Garzik struct ahci_cmd_hdr { 174c6fd2807SJeff Garzik u32 opts; 175c6fd2807SJeff Garzik u32 status; 176c6fd2807SJeff Garzik u32 tbl_addr; 177c6fd2807SJeff Garzik u32 tbl_addr_hi; 178c6fd2807SJeff Garzik u32 reserved[4]; 179c6fd2807SJeff Garzik }; 180c6fd2807SJeff Garzik 181c6fd2807SJeff Garzik struct ahci_sg { 182c6fd2807SJeff Garzik u32 addr; 183c6fd2807SJeff Garzik u32 addr_hi; 184c6fd2807SJeff Garzik u32 reserved; 185c6fd2807SJeff Garzik u32 flags_size; 186c6fd2807SJeff Garzik }; 187c6fd2807SJeff Garzik 188c6fd2807SJeff Garzik struct ahci_host_priv { 189c6fd2807SJeff Garzik u32 cap; /* cache of HOST_CAP register */ 190c6fd2807SJeff Garzik u32 port_map; /* cache of HOST_PORTS_IMPL reg */ 191c6fd2807SJeff Garzik }; 192c6fd2807SJeff Garzik 193c6fd2807SJeff Garzik struct ahci_port_priv { 194c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 195c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 196c6fd2807SJeff Garzik void *cmd_tbl; 197c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 198c6fd2807SJeff Garzik void *rx_fis; 199c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2000291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2010291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2020291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 203afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 204c6fd2807SJeff Garzik }; 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); 207c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 208c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 209c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 2107d12e780SDavid Howells static irqreturn_t ahci_interrupt (int irq, void *dev_instance); 211c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap); 212c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 213c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 214c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 215c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 216c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap); 217c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 218c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 219c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 220ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap); 221c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 222*438ac6d5STejun Heo #ifdef CONFIG_PM 223c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 224c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 225c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 226c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 227*438ac6d5STejun Heo #endif 228c6fd2807SJeff Garzik 229c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 230c6fd2807SJeff Garzik .module = THIS_MODULE, 231c6fd2807SJeff Garzik .name = DRV_NAME, 232c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 233c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 234c6fd2807SJeff Garzik .change_queue_depth = ata_scsi_change_queue_depth, 235c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 236c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 237c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 238c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 239c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 240c6fd2807SJeff Garzik .use_clustering = AHCI_USE_CLUSTERING, 241c6fd2807SJeff Garzik .proc_name = DRV_NAME, 242c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 243c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 244c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 245c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 246*438ac6d5STejun Heo #ifdef CONFIG_PM 247c6fd2807SJeff Garzik .suspend = ata_scsi_device_suspend, 248c6fd2807SJeff Garzik .resume = ata_scsi_device_resume, 249*438ac6d5STejun Heo #endif 250c6fd2807SJeff Garzik }; 251c6fd2807SJeff Garzik 252c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = { 253c6fd2807SJeff Garzik .port_disable = ata_port_disable, 254c6fd2807SJeff Garzik 255c6fd2807SJeff Garzik .check_status = ahci_check_status, 256c6fd2807SJeff Garzik .check_altstatus = ahci_check_status, 257c6fd2807SJeff Garzik .dev_select = ata_noop_dev_select, 258c6fd2807SJeff Garzik 259c6fd2807SJeff Garzik .tf_read = ahci_tf_read, 260c6fd2807SJeff Garzik 261c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 262c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 263c6fd2807SJeff Garzik 264c6fd2807SJeff Garzik .irq_handler = ahci_interrupt, 265c6fd2807SJeff Garzik .irq_clear = ahci_irq_clear, 266246ce3b6SAkira Iguchi .irq_on = ata_dummy_irq_on, 267246ce3b6SAkira Iguchi .irq_ack = ata_dummy_irq_ack, 268c6fd2807SJeff Garzik 269c6fd2807SJeff Garzik .scr_read = ahci_scr_read, 270c6fd2807SJeff Garzik .scr_write = ahci_scr_write, 271c6fd2807SJeff Garzik 272c6fd2807SJeff Garzik .freeze = ahci_freeze, 273c6fd2807SJeff Garzik .thaw = ahci_thaw, 274c6fd2807SJeff Garzik 275c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 276c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 277c6fd2807SJeff Garzik 278*438ac6d5STejun Heo #ifdef CONFIG_PM 279c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 280c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 281*438ac6d5STejun Heo #endif 282c6fd2807SJeff Garzik 283c6fd2807SJeff Garzik .port_start = ahci_port_start, 284c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 285c6fd2807SJeff Garzik }; 286c6fd2807SJeff Garzik 287ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = { 288ad616ffbSTejun Heo .port_disable = ata_port_disable, 289ad616ffbSTejun Heo 290ad616ffbSTejun Heo .check_status = ahci_check_status, 291ad616ffbSTejun Heo .check_altstatus = ahci_check_status, 292ad616ffbSTejun Heo .dev_select = ata_noop_dev_select, 293ad616ffbSTejun Heo 294ad616ffbSTejun Heo .tf_read = ahci_tf_read, 295ad616ffbSTejun Heo 296ad616ffbSTejun Heo .qc_prep = ahci_qc_prep, 297ad616ffbSTejun Heo .qc_issue = ahci_qc_issue, 298ad616ffbSTejun Heo 299ad616ffbSTejun Heo .irq_handler = ahci_interrupt, 300ad616ffbSTejun Heo .irq_clear = ahci_irq_clear, 301246ce3b6SAkira Iguchi .irq_on = ata_dummy_irq_on, 302246ce3b6SAkira Iguchi .irq_ack = ata_dummy_irq_ack, 303ad616ffbSTejun Heo 304ad616ffbSTejun Heo .scr_read = ahci_scr_read, 305ad616ffbSTejun Heo .scr_write = ahci_scr_write, 306ad616ffbSTejun Heo 307ad616ffbSTejun Heo .freeze = ahci_freeze, 308ad616ffbSTejun Heo .thaw = ahci_thaw, 309ad616ffbSTejun Heo 310ad616ffbSTejun Heo .error_handler = ahci_vt8251_error_handler, 311ad616ffbSTejun Heo .post_internal_cmd = ahci_post_internal_cmd, 312ad616ffbSTejun Heo 313*438ac6d5STejun Heo #ifdef CONFIG_PM 314ad616ffbSTejun Heo .port_suspend = ahci_port_suspend, 315ad616ffbSTejun Heo .port_resume = ahci_port_resume, 316*438ac6d5STejun Heo #endif 317ad616ffbSTejun Heo 318ad616ffbSTejun Heo .port_start = ahci_port_start, 319ad616ffbSTejun Heo .port_stop = ahci_port_stop, 320ad616ffbSTejun Heo }; 321ad616ffbSTejun Heo 322c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 323c6fd2807SJeff Garzik /* board_ahci */ 324c6fd2807SJeff Garzik { 325c6fd2807SJeff Garzik .sht = &ahci_sht, 326cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 327c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 328c6fd2807SJeff Garzik ATA_FLAG_SKIP_D2H_BSY, 329c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 330c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 331c6fd2807SJeff Garzik .port_ops = &ahci_ops, 332c6fd2807SJeff Garzik }, 333648a88beSTejun Heo /* board_ahci_pi */ 334648a88beSTejun Heo { 335648a88beSTejun Heo .sht = &ahci_sht, 336648a88beSTejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 337648a88beSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 338648a88beSTejun Heo ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, 339648a88beSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 340648a88beSTejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 341648a88beSTejun Heo .port_ops = &ahci_ops, 342648a88beSTejun Heo }, 343c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 344c6fd2807SJeff Garzik { 345c6fd2807SJeff Garzik .sht = &ahci_sht, 346cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 347c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 348ad616ffbSTejun Heo ATA_FLAG_SKIP_D2H_BSY | 349ad616ffbSTejun Heo ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, 350c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 351c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 352ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 353c6fd2807SJeff Garzik }, 35441669553STejun Heo /* board_ahci_ign_iferr */ 35541669553STejun Heo { 35641669553STejun Heo .sht = &ahci_sht, 35741669553STejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 35841669553STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 35941669553STejun Heo ATA_FLAG_SKIP_D2H_BSY | 36041669553STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR, 36141669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 36241669553STejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 36341669553STejun Heo .port_ops = &ahci_ops, 36441669553STejun Heo }, 365c6fd2807SJeff Garzik }; 366c6fd2807SJeff Garzik 367c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 368c6fd2807SJeff Garzik /* Intel */ 36954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 37054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 37154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 37254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 37354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 37482490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 37554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 37654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 37754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 37854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 379648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ 380648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ 381648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ 382648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ 383648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ 384648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ 385648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ 386648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ 387648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ 388648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ 389648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ 390648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ 391648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ 392648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ 393648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ 394648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ 395c6fd2807SJeff Garzik 396e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 397e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 398e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 399c6fd2807SJeff Garzik 400c6fd2807SJeff Garzik /* ATI */ 40154bb3a94SJeff Garzik { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */ 40254bb3a94SJeff Garzik { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */ 403c6fd2807SJeff Garzik 404c6fd2807SJeff Garzik /* VIA */ 40554bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 406c6fd2807SJeff Garzik 407c6fd2807SJeff Garzik /* NVIDIA */ 40854bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ 40954bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ 41054bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ 41154bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ 4126fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ 4136fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ 4146fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ 4156fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ 4166fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 4176fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 4186fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 4196fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 420895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 421895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 422895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 423895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 424895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 425895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 426895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 427895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 428c6fd2807SJeff Garzik 429c6fd2807SJeff Garzik /* SiS */ 43054bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 43154bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 43254bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 433c6fd2807SJeff Garzik 434415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 435415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 436c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 437415ae2b5SJeff Garzik 438c6fd2807SJeff Garzik { } /* terminate list */ 439c6fd2807SJeff Garzik }; 440c6fd2807SJeff Garzik 441c6fd2807SJeff Garzik 442c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 443c6fd2807SJeff Garzik .name = DRV_NAME, 444c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 445c6fd2807SJeff Garzik .probe = ahci_init_one, 44624dc5f33STejun Heo .remove = ata_pci_remove_one, 447*438ac6d5STejun Heo #ifdef CONFIG_PM 448c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 449c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 450*438ac6d5STejun Heo #endif 451c6fd2807SJeff Garzik }; 452c6fd2807SJeff Garzik 453c6fd2807SJeff Garzik 45498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 45598fa4b60STejun Heo { 45698fa4b60STejun Heo return (cap & 0x1f) + 1; 45798fa4b60STejun Heo } 45898fa4b60STejun Heo 4590d5ff566STejun Heo static inline void __iomem *ahci_port_base(void __iomem *base, 4600d5ff566STejun Heo unsigned int port) 461c6fd2807SJeff Garzik { 462c6fd2807SJeff Garzik return base + 0x100 + (port * 0x80); 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 4780d5ff566STejun Heo return readl(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 4960d5ff566STejun Heo writel(val, 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 590*438ac6d5STejun Heo #ifdef CONFIG_PM 591c6fd2807SJeff Garzik static void ahci_power_down(void __iomem *port_mmio, u32 cap) 592c6fd2807SJeff Garzik { 593c6fd2807SJeff Garzik u32 cmd, scontrol; 594c6fd2807SJeff Garzik 59507c53dacSTejun Heo if (!(cap & HOST_CAP_SSS)) 59607c53dacSTejun Heo return; 597c6fd2807SJeff Garzik 59807c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 599c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 600c6fd2807SJeff Garzik scontrol &= ~0xf; 601c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 602c6fd2807SJeff Garzik 603c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 60407c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 605c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 606c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 607c6fd2807SJeff Garzik } 608*438ac6d5STejun Heo #endif 609c6fd2807SJeff Garzik 610c6fd2807SJeff Garzik static void ahci_init_port(void __iomem *port_mmio, u32 cap, 611c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) 612c6fd2807SJeff Garzik { 613c6fd2807SJeff Garzik /* enable FIS reception */ 614c6fd2807SJeff Garzik ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma); 615c6fd2807SJeff Garzik 616c6fd2807SJeff Garzik /* enable DMA */ 617c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 618c6fd2807SJeff Garzik } 619c6fd2807SJeff Garzik 620c6fd2807SJeff Garzik static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) 621c6fd2807SJeff Garzik { 622c6fd2807SJeff Garzik int rc; 623c6fd2807SJeff Garzik 624c6fd2807SJeff Garzik /* disable DMA */ 625c6fd2807SJeff Garzik rc = ahci_stop_engine(port_mmio); 626c6fd2807SJeff Garzik if (rc) { 627c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 628c6fd2807SJeff Garzik return rc; 629c6fd2807SJeff Garzik } 630c6fd2807SJeff Garzik 631c6fd2807SJeff Garzik /* disable FIS reception */ 632c6fd2807SJeff Garzik rc = ahci_stop_fis_rx(port_mmio); 633c6fd2807SJeff Garzik if (rc) { 634c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 635c6fd2807SJeff Garzik return rc; 636c6fd2807SJeff Garzik } 637c6fd2807SJeff Garzik 638c6fd2807SJeff Garzik return 0; 639c6fd2807SJeff Garzik } 640c6fd2807SJeff Garzik 641c6fd2807SJeff Garzik static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) 642c6fd2807SJeff Garzik { 64398fa4b60STejun Heo u32 cap_save, impl_save, tmp; 644c6fd2807SJeff Garzik 645c6fd2807SJeff Garzik cap_save = readl(mmio + HOST_CAP); 64698fa4b60STejun Heo impl_save = readl(mmio + HOST_PORTS_IMPL); 647c6fd2807SJeff Garzik 648c6fd2807SJeff Garzik /* global controller reset */ 649c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 650c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 651c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 652c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 653c6fd2807SJeff Garzik } 654c6fd2807SJeff Garzik 655c6fd2807SJeff Garzik /* reset must complete within 1 second, or 656c6fd2807SJeff Garzik * the hardware should be considered fried. 657c6fd2807SJeff Garzik */ 658c6fd2807SJeff Garzik ssleep(1); 659c6fd2807SJeff Garzik 660c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 661c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 662c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 663c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 664c6fd2807SJeff Garzik return -EIO; 665c6fd2807SJeff Garzik } 666c6fd2807SJeff Garzik 66798fa4b60STejun Heo /* turn on AHCI mode */ 668c6fd2807SJeff Garzik writel(HOST_AHCI_EN, mmio + HOST_CTL); 669c6fd2807SJeff Garzik (void) readl(mmio + HOST_CTL); /* flush */ 67098fa4b60STejun Heo 67198fa4b60STejun Heo /* These write-once registers are normally cleared on reset. 67298fa4b60STejun Heo * Restore BIOS values... which we HOPE were present before 67398fa4b60STejun Heo * reset. 67498fa4b60STejun Heo */ 67598fa4b60STejun Heo if (!impl_save) { 67698fa4b60STejun Heo impl_save = (1 << ahci_nr_ports(cap_save)) - 1; 67798fa4b60STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 67898fa4b60STejun Heo "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); 67998fa4b60STejun Heo } 680c6fd2807SJeff Garzik writel(cap_save, mmio + HOST_CAP); 68198fa4b60STejun Heo writel(impl_save, mmio + HOST_PORTS_IMPL); 682c6fd2807SJeff Garzik (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 683c6fd2807SJeff Garzik 684c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 685c6fd2807SJeff Garzik u16 tmp16; 686c6fd2807SJeff Garzik 687c6fd2807SJeff Garzik /* configure PCS */ 688c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 689c6fd2807SJeff Garzik tmp16 |= 0xf; 690c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 691c6fd2807SJeff Garzik } 692c6fd2807SJeff Garzik 693c6fd2807SJeff Garzik return 0; 694c6fd2807SJeff Garzik } 695c6fd2807SJeff Garzik 696c6fd2807SJeff Garzik static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, 697648a88beSTejun Heo int n_ports, unsigned int port_flags, 698648a88beSTejun Heo struct ahci_host_priv *hpriv) 699c6fd2807SJeff Garzik { 700c6fd2807SJeff Garzik int i, rc; 701c6fd2807SJeff Garzik u32 tmp; 702c6fd2807SJeff Garzik 703c6fd2807SJeff Garzik for (i = 0; i < n_ports; i++) { 704c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, i); 705c6fd2807SJeff Garzik const char *emsg = NULL; 706c6fd2807SJeff Garzik 707648a88beSTejun Heo if ((port_flags & AHCI_FLAG_HONOR_PI) && 708648a88beSTejun Heo !(hpriv->port_map & (1 << i))) 709c6fd2807SJeff Garzik continue; 710c6fd2807SJeff Garzik 711c6fd2807SJeff Garzik /* make sure port is not active */ 712648a88beSTejun Heo rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 713c6fd2807SJeff Garzik if (rc) 714c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 715c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 716c6fd2807SJeff Garzik 717c6fd2807SJeff Garzik /* clear SError */ 718c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 719c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 720c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 721c6fd2807SJeff Garzik 722c6fd2807SJeff Garzik /* clear port IRQ */ 723c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 724c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 725c6fd2807SJeff Garzik if (tmp) 726c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 727c6fd2807SJeff Garzik 728c6fd2807SJeff Garzik writel(1 << i, mmio + HOST_IRQ_STAT); 729c6fd2807SJeff Garzik } 730c6fd2807SJeff Garzik 731c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 732c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 733c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 734c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 735c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 736c6fd2807SJeff Garzik } 737c6fd2807SJeff Garzik 738c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 739c6fd2807SJeff Garzik { 7400d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 741c6fd2807SJeff Garzik struct ata_taskfile tf; 742c6fd2807SJeff Garzik u32 tmp; 743c6fd2807SJeff Garzik 744c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 745c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 746c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 747c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 748c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 749c6fd2807SJeff Garzik 750c6fd2807SJeff Garzik return ata_dev_classify(&tf); 751c6fd2807SJeff Garzik } 752c6fd2807SJeff Garzik 753c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 754c6fd2807SJeff Garzik u32 opts) 755c6fd2807SJeff Garzik { 756c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 757c6fd2807SJeff Garzik 758c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 759c6fd2807SJeff Garzik 760c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 761c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 762c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 763c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 764c6fd2807SJeff Garzik } 765c6fd2807SJeff Garzik 766c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap) 767c6fd2807SJeff Garzik { 7680d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 769cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 770c6fd2807SJeff Garzik u32 tmp; 771c6fd2807SJeff Garzik 772c6fd2807SJeff Garzik if (!(hpriv->cap & HOST_CAP_CLO)) 773c6fd2807SJeff Garzik return -EOPNOTSUPP; 774c6fd2807SJeff Garzik 775c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 776c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 777c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 778c6fd2807SJeff Garzik 779c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 780c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 781c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 782c6fd2807SJeff Garzik return -EIO; 783c6fd2807SJeff Garzik 784c6fd2807SJeff Garzik return 0; 785c6fd2807SJeff Garzik } 786c6fd2807SJeff Garzik 787c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class) 788c6fd2807SJeff Garzik { 789c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 7900d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 791c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 792c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 793c6fd2807SJeff Garzik const char *reason = NULL; 794c6fd2807SJeff Garzik struct ata_taskfile tf; 795c6fd2807SJeff Garzik u32 tmp; 796c6fd2807SJeff Garzik u8 *fis; 797c6fd2807SJeff Garzik int rc; 798c6fd2807SJeff Garzik 799c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 800c6fd2807SJeff Garzik 801c6fd2807SJeff Garzik if (ata_port_offline(ap)) { 802c6fd2807SJeff Garzik DPRINTK("PHY reports no device\n"); 803c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 804c6fd2807SJeff Garzik return 0; 805c6fd2807SJeff Garzik } 806c6fd2807SJeff Garzik 807c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 808c6fd2807SJeff Garzik rc = ahci_stop_engine(port_mmio); 809c6fd2807SJeff Garzik if (rc) { 810c6fd2807SJeff Garzik reason = "failed to stop engine"; 811c6fd2807SJeff Garzik goto fail_restart; 812c6fd2807SJeff Garzik } 813c6fd2807SJeff Garzik 814c6fd2807SJeff Garzik /* check BUSY/DRQ, perform Command List Override if necessary */ 8151244a19cSTejun Heo if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) { 816c6fd2807SJeff Garzik rc = ahci_clo(ap); 817c6fd2807SJeff Garzik 818c6fd2807SJeff Garzik if (rc == -EOPNOTSUPP) { 819c6fd2807SJeff Garzik reason = "port busy but CLO unavailable"; 820c6fd2807SJeff Garzik goto fail_restart; 821c6fd2807SJeff Garzik } else if (rc) { 822c6fd2807SJeff Garzik reason = "port busy but CLO failed"; 823c6fd2807SJeff Garzik goto fail_restart; 824c6fd2807SJeff Garzik } 825c6fd2807SJeff Garzik } 826c6fd2807SJeff Garzik 827c6fd2807SJeff Garzik /* restart engine */ 828c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 829c6fd2807SJeff Garzik 830c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 831c6fd2807SJeff Garzik fis = pp->cmd_tbl; 832c6fd2807SJeff Garzik 833c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 834c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, 835c6fd2807SJeff Garzik cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); 836c6fd2807SJeff Garzik 837c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 838c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 839c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 840c6fd2807SJeff Garzik 841c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 842c6fd2807SJeff Garzik 843c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500); 844c6fd2807SJeff Garzik if (tmp & 0x1) { 845c6fd2807SJeff Garzik rc = -EIO; 846c6fd2807SJeff Garzik reason = "1st FIS failed"; 847c6fd2807SJeff Garzik goto fail; 848c6fd2807SJeff Garzik } 849c6fd2807SJeff Garzik 850c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 851c6fd2807SJeff Garzik msleep(1); 852c6fd2807SJeff Garzik 853c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 854c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, cmd_fis_len); 855c6fd2807SJeff Garzik 856c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 857c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 858c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 859c6fd2807SJeff Garzik 860c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 861c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 862c6fd2807SJeff Garzik 863c6fd2807SJeff Garzik /* spec mandates ">= 2ms" before checking status. 864c6fd2807SJeff Garzik * We wait 150ms, because that was the magic delay used for 865c6fd2807SJeff Garzik * ATAPI devices in Hale Landis's ATADRVR, for the period of time 866c6fd2807SJeff Garzik * between when the ATA command register is written, and then 867c6fd2807SJeff Garzik * status is checked. Because waiting for "a while" before 868c6fd2807SJeff Garzik * checking status is fine, post SRST, we perform this magic 869c6fd2807SJeff Garzik * delay here as well. 870c6fd2807SJeff Garzik */ 871c6fd2807SJeff Garzik msleep(150); 872c6fd2807SJeff Garzik 873c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 874c6fd2807SJeff Garzik if (ata_port_online(ap)) { 875c6fd2807SJeff Garzik if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { 876c6fd2807SJeff Garzik rc = -EIO; 877c6fd2807SJeff Garzik reason = "device not ready"; 878c6fd2807SJeff Garzik goto fail; 879c6fd2807SJeff Garzik } 880c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 881c6fd2807SJeff Garzik } 882c6fd2807SJeff Garzik 883c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 884c6fd2807SJeff Garzik return 0; 885c6fd2807SJeff Garzik 886c6fd2807SJeff Garzik fail_restart: 887c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 888c6fd2807SJeff Garzik fail: 889c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); 890c6fd2807SJeff Garzik return rc; 891c6fd2807SJeff Garzik } 892c6fd2807SJeff Garzik 893c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class) 894c6fd2807SJeff Garzik { 895c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 896c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 897c6fd2807SJeff Garzik struct ata_taskfile tf; 8980d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 899c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 900c6fd2807SJeff Garzik int rc; 901c6fd2807SJeff Garzik 902c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 903c6fd2807SJeff Garzik 904c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 905c6fd2807SJeff Garzik 906c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 907c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 908dfd7a3dbSTejun Heo tf.command = 0x80; 909c6fd2807SJeff Garzik ata_tf_to_fis(&tf, d2h_fis, 0); 910c6fd2807SJeff Garzik 911c6fd2807SJeff Garzik rc = sata_std_hardreset(ap, class); 912c6fd2807SJeff Garzik 913c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 914c6fd2807SJeff Garzik 915c6fd2807SJeff Garzik if (rc == 0 && ata_port_online(ap)) 916c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 917c6fd2807SJeff Garzik if (*class == ATA_DEV_UNKNOWN) 918c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 919c6fd2807SJeff Garzik 920c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 921c6fd2807SJeff Garzik return rc; 922c6fd2807SJeff Garzik } 923c6fd2807SJeff Garzik 924ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) 925ad616ffbSTejun Heo { 9260d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 927ad616ffbSTejun Heo void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 928ad616ffbSTejun Heo int rc; 929ad616ffbSTejun Heo 930ad616ffbSTejun Heo DPRINTK("ENTER\n"); 931ad616ffbSTejun Heo 932ad616ffbSTejun Heo ahci_stop_engine(port_mmio); 933ad616ffbSTejun Heo 934ad616ffbSTejun Heo rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); 935ad616ffbSTejun Heo 936ad616ffbSTejun Heo /* vt8251 needs SError cleared for the port to operate */ 937ad616ffbSTejun Heo ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); 938ad616ffbSTejun Heo 939ad616ffbSTejun Heo ahci_start_engine(port_mmio); 940ad616ffbSTejun Heo 941ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 942ad616ffbSTejun Heo 943ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 944ad616ffbSTejun Heo * request follow-up softreset. 945ad616ffbSTejun Heo */ 946ad616ffbSTejun Heo return rc ?: -EAGAIN; 947ad616ffbSTejun Heo } 948ad616ffbSTejun Heo 949c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class) 950c6fd2807SJeff Garzik { 9510d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 952c6fd2807SJeff Garzik u32 new_tmp, tmp; 953c6fd2807SJeff Garzik 954c6fd2807SJeff Garzik ata_std_postreset(ap, class); 955c6fd2807SJeff Garzik 956c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 957c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 958c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 959c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 960c6fd2807SJeff Garzik else 961c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 962c6fd2807SJeff Garzik if (new_tmp != tmp) { 963c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 964c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 965c6fd2807SJeff Garzik } 966c6fd2807SJeff Garzik } 967c6fd2807SJeff Garzik 968c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap) 969c6fd2807SJeff Garzik { 9700d5ff566STejun Heo void __iomem *mmio = ap->ioaddr.cmd_addr; 971c6fd2807SJeff Garzik 972c6fd2807SJeff Garzik return readl(mmio + PORT_TFDATA) & 0xFF; 973c6fd2807SJeff Garzik } 974c6fd2807SJeff Garzik 975c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 976c6fd2807SJeff Garzik { 977c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 978c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 979c6fd2807SJeff Garzik 980c6fd2807SJeff Garzik ata_tf_from_fis(d2h_fis, tf); 981c6fd2807SJeff Garzik } 982c6fd2807SJeff Garzik 983c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 984c6fd2807SJeff Garzik { 985c6fd2807SJeff Garzik struct scatterlist *sg; 986c6fd2807SJeff Garzik struct ahci_sg *ahci_sg; 987c6fd2807SJeff Garzik unsigned int n_sg = 0; 988c6fd2807SJeff Garzik 989c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 990c6fd2807SJeff Garzik 991c6fd2807SJeff Garzik /* 992c6fd2807SJeff Garzik * Next, the S/G list. 993c6fd2807SJeff Garzik */ 994c6fd2807SJeff Garzik ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 995c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 996c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 997c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 998c6fd2807SJeff Garzik 999c6fd2807SJeff Garzik ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); 1000c6fd2807SJeff Garzik ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); 1001c6fd2807SJeff Garzik ahci_sg->flags_size = cpu_to_le32(sg_len - 1); 1002c6fd2807SJeff Garzik 1003c6fd2807SJeff Garzik ahci_sg++; 1004c6fd2807SJeff Garzik n_sg++; 1005c6fd2807SJeff Garzik } 1006c6fd2807SJeff Garzik 1007c6fd2807SJeff Garzik return n_sg; 1008c6fd2807SJeff Garzik } 1009c6fd2807SJeff Garzik 1010c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1011c6fd2807SJeff Garzik { 1012c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1013c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1014c6fd2807SJeff Garzik int is_atapi = is_atapi_taskfile(&qc->tf); 1015c6fd2807SJeff Garzik void *cmd_tbl; 1016c6fd2807SJeff Garzik u32 opts; 1017c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1018c6fd2807SJeff Garzik unsigned int n_elem; 1019c6fd2807SJeff Garzik 1020c6fd2807SJeff Garzik /* 1021c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1022c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1023c6fd2807SJeff Garzik */ 1024c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1025c6fd2807SJeff Garzik 1026c6fd2807SJeff Garzik ata_tf_to_fis(&qc->tf, cmd_tbl, 0); 1027c6fd2807SJeff Garzik if (is_atapi) { 1028c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1029c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1030c6fd2807SJeff Garzik } 1031c6fd2807SJeff Garzik 1032c6fd2807SJeff Garzik n_elem = 0; 1033c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1034c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1035c6fd2807SJeff Garzik 1036c6fd2807SJeff Garzik /* 1037c6fd2807SJeff Garzik * Fill in command slot information. 1038c6fd2807SJeff Garzik */ 1039c6fd2807SJeff Garzik opts = cmd_fis_len | n_elem << 16; 1040c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1041c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1042c6fd2807SJeff Garzik if (is_atapi) 1043c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1044c6fd2807SJeff Garzik 1045c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1046c6fd2807SJeff Garzik } 1047c6fd2807SJeff Garzik 1048c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1049c6fd2807SJeff Garzik { 1050c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1051c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 1052c6fd2807SJeff Garzik unsigned int err_mask = 0, action = 0; 1053c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 1054c6fd2807SJeff Garzik u32 serror; 1055c6fd2807SJeff Garzik 1056c6fd2807SJeff Garzik ata_ehi_clear_desc(ehi); 1057c6fd2807SJeff Garzik 1058c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1059c6fd2807SJeff Garzik serror = ahci_scr_read(ap, SCR_ERROR); 1060c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 1061c6fd2807SJeff Garzik 1062c6fd2807SJeff Garzik /* analyze @irq_stat */ 1063c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); 1064c6fd2807SJeff Garzik 106541669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 106641669553STejun Heo if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) 106741669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 106841669553STejun Heo 1069c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_TF_ERR) 1070c6fd2807SJeff Garzik err_mask |= AC_ERR_DEV; 1071c6fd2807SJeff Garzik 1072c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 1073c6fd2807SJeff Garzik err_mask |= AC_ERR_HOST_BUS; 1074c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1075c6fd2807SJeff Garzik } 1076c6fd2807SJeff Garzik 1077c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_IF_ERR) { 1078c6fd2807SJeff Garzik err_mask |= AC_ERR_ATA_BUS; 1079c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1080c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", interface fatal error"); 1081c6fd2807SJeff Garzik } 1082c6fd2807SJeff Garzik 1083c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 1084c6fd2807SJeff Garzik ata_ehi_hotplugged(ehi); 1085c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? 1086c6fd2807SJeff Garzik "connection status changed" : "PHY RDY changed"); 1087c6fd2807SJeff Garzik } 1088c6fd2807SJeff Garzik 1089c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1090c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1091c6fd2807SJeff Garzik 1092c6fd2807SJeff Garzik err_mask |= AC_ERR_HSM; 1093c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1094c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", 1095c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1096c6fd2807SJeff Garzik } 1097c6fd2807SJeff Garzik 1098c6fd2807SJeff Garzik /* okay, let's hand over to EH */ 1099c6fd2807SJeff Garzik ehi->serror |= serror; 1100c6fd2807SJeff Garzik ehi->action |= action; 1101c6fd2807SJeff Garzik 1102c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 1103c6fd2807SJeff Garzik if (qc) 1104c6fd2807SJeff Garzik qc->err_mask |= err_mask; 1105c6fd2807SJeff Garzik else 1106c6fd2807SJeff Garzik ehi->err_mask |= err_mask; 1107c6fd2807SJeff Garzik 1108c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1109c6fd2807SJeff Garzik ata_port_freeze(ap); 1110c6fd2807SJeff Garzik else 1111c6fd2807SJeff Garzik ata_port_abort(ap); 1112c6fd2807SJeff Garzik } 1113c6fd2807SJeff Garzik 1114c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap) 1115c6fd2807SJeff Garzik { 11160d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1117c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1118c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 11190291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 1120c6fd2807SJeff Garzik u32 status, qc_active; 11210291f95fSTejun Heo int rc, known_irq = 0; 1122c6fd2807SJeff Garzik 1123c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1124c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1125c6fd2807SJeff Garzik 1126c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1127c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1128c6fd2807SJeff Garzik return; 1129c6fd2807SJeff Garzik } 1130c6fd2807SJeff Garzik 1131c6fd2807SJeff Garzik if (ap->sactive) 1132c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1133c6fd2807SJeff Garzik else 1134c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1135c6fd2807SJeff Garzik 1136c6fd2807SJeff Garzik rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1137c6fd2807SJeff Garzik if (rc > 0) 1138c6fd2807SJeff Garzik return; 1139c6fd2807SJeff Garzik if (rc < 0) { 1140c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1141c6fd2807SJeff Garzik ehi->action |= ATA_EH_SOFTRESET; 1142c6fd2807SJeff Garzik ata_port_freeze(ap); 1143c6fd2807SJeff Garzik return; 1144c6fd2807SJeff Garzik } 1145c6fd2807SJeff Garzik 1146c6fd2807SJeff Garzik /* hmmm... a spurious interupt */ 1147c6fd2807SJeff Garzik 11480291f95fSTejun Heo /* if !NCQ, ignore. No modern ATA device has broken HSM 11490291f95fSTejun Heo * implementation for non-NCQ commands. 11500291f95fSTejun Heo */ 11510291f95fSTejun Heo if (!ap->sactive) 1152c6fd2807SJeff Garzik return; 1153c6fd2807SJeff Garzik 11540291f95fSTejun Heo if (status & PORT_IRQ_D2H_REG_FIS) { 11550291f95fSTejun Heo if (!pp->ncq_saw_d2h) 11560291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 11570291f95fSTejun Heo "D2H reg with I during NCQ, " 11580291f95fSTejun Heo "this message won't be printed again\n"); 11590291f95fSTejun Heo pp->ncq_saw_d2h = 1; 11600291f95fSTejun Heo known_irq = 1; 11610291f95fSTejun Heo } 1162c6fd2807SJeff Garzik 11630291f95fSTejun Heo if (status & PORT_IRQ_DMAS_FIS) { 11640291f95fSTejun Heo if (!pp->ncq_saw_dmas) 11650291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 11660291f95fSTejun Heo "DMAS FIS during NCQ, " 11670291f95fSTejun Heo "this message won't be printed again\n"); 11680291f95fSTejun Heo pp->ncq_saw_dmas = 1; 11690291f95fSTejun Heo known_irq = 1; 11700291f95fSTejun Heo } 11710291f95fSTejun Heo 1172a2bbd0c9STejun Heo if (status & PORT_IRQ_SDB_FIS) { 117304d4f7a1SAl Viro const __le32 *f = pp->rx_fis + RX_FIS_SDB; 11740291f95fSTejun Heo 1175afb2d552STejun Heo if (le32_to_cpu(f[1])) { 1176afb2d552STejun Heo /* SDB FIS containing spurious completions 1177afb2d552STejun Heo * might be dangerous, whine and fail commands 1178afb2d552STejun Heo * with HSM violation. EH will turn off NCQ 1179afb2d552STejun Heo * after several such failures. 1180afb2d552STejun Heo */ 1181afb2d552STejun Heo ata_ehi_push_desc(ehi, 1182afb2d552STejun Heo "spurious completions during NCQ " 1183a2bbd0c9STejun Heo "issue=0x%x SAct=0x%x FIS=%08x:%08x", 11840291f95fSTejun Heo readl(port_mmio + PORT_CMD_ISSUE), 11856096b63eSTejun Heo readl(port_mmio + PORT_SCR_ACT), 1186a2bbd0c9STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1187a2bbd0c9STejun Heo ehi->err_mask |= AC_ERR_HSM; 1188a2bbd0c9STejun Heo ehi->action |= ATA_EH_SOFTRESET; 1189a2bbd0c9STejun Heo ata_port_freeze(ap); 1190afb2d552STejun Heo } else { 1191afb2d552STejun Heo if (!pp->ncq_saw_sdb) 1192afb2d552STejun Heo ata_port_printk(ap, KERN_INFO, 1193afb2d552STejun Heo "spurious SDB FIS %08x:%08x during NCQ, " 1194afb2d552STejun Heo "this message won't be printed again\n", 1195afb2d552STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1196afb2d552STejun Heo pp->ncq_saw_sdb = 1; 1197afb2d552STejun Heo } 11980291f95fSTejun Heo known_irq = 1; 11990291f95fSTejun Heo } 12000291f95fSTejun Heo 12010291f95fSTejun Heo if (!known_irq) 1202c6fd2807SJeff Garzik ata_port_printk(ap, KERN_INFO, "spurious interrupt " 12030291f95fSTejun Heo "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", 1204c6fd2807SJeff Garzik status, ap->active_tag, ap->sactive); 1205c6fd2807SJeff Garzik } 1206c6fd2807SJeff Garzik 1207c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap) 1208c6fd2807SJeff Garzik { 1209c6fd2807SJeff Garzik /* TODO */ 1210c6fd2807SJeff Garzik } 1211c6fd2807SJeff Garzik 12127d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1213c6fd2807SJeff Garzik { 1214cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1215c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1216c6fd2807SJeff Garzik unsigned int i, handled = 0; 1217c6fd2807SJeff Garzik void __iomem *mmio; 1218c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1219c6fd2807SJeff Garzik 1220c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1221c6fd2807SJeff Garzik 1222cca3974eSJeff Garzik hpriv = host->private_data; 12230d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 1224c6fd2807SJeff Garzik 1225c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1226c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1227c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1228c6fd2807SJeff Garzik if (!irq_stat) 1229c6fd2807SJeff Garzik return IRQ_NONE; 1230c6fd2807SJeff Garzik 1231cca3974eSJeff Garzik spin_lock(&host->lock); 1232c6fd2807SJeff Garzik 1233cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1234c6fd2807SJeff Garzik struct ata_port *ap; 1235c6fd2807SJeff Garzik 1236c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1237c6fd2807SJeff Garzik continue; 1238c6fd2807SJeff Garzik 1239cca3974eSJeff Garzik ap = host->ports[i]; 1240c6fd2807SJeff Garzik if (ap) { 1241c6fd2807SJeff Garzik ahci_host_intr(ap); 1242c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1243c6fd2807SJeff Garzik } else { 1244c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1245c6fd2807SJeff Garzik if (ata_ratelimit()) 1246cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1247c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1248c6fd2807SJeff Garzik } 1249c6fd2807SJeff Garzik 1250c6fd2807SJeff Garzik irq_ack |= (1 << i); 1251c6fd2807SJeff Garzik } 1252c6fd2807SJeff Garzik 1253c6fd2807SJeff Garzik if (irq_ack) { 1254c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1255c6fd2807SJeff Garzik handled = 1; 1256c6fd2807SJeff Garzik } 1257c6fd2807SJeff Garzik 1258cca3974eSJeff Garzik spin_unlock(&host->lock); 1259c6fd2807SJeff Garzik 1260c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1261c6fd2807SJeff Garzik 1262c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1263c6fd2807SJeff Garzik } 1264c6fd2807SJeff Garzik 1265c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1266c6fd2807SJeff Garzik { 1267c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 12680d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 1269c6fd2807SJeff Garzik 1270c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1271c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1272c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1273c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1274c6fd2807SJeff Garzik 1275c6fd2807SJeff Garzik return 0; 1276c6fd2807SJeff Garzik } 1277c6fd2807SJeff Garzik 1278c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1279c6fd2807SJeff Garzik { 12800d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1281c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1282c6fd2807SJeff Garzik 1283c6fd2807SJeff Garzik /* turn IRQ off */ 1284c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1285c6fd2807SJeff Garzik } 1286c6fd2807SJeff Garzik 1287c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1288c6fd2807SJeff Garzik { 12890d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1290c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1291c6fd2807SJeff Garzik u32 tmp; 1292c6fd2807SJeff Garzik 1293c6fd2807SJeff Garzik /* clear IRQ */ 1294c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1295c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1296a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1297c6fd2807SJeff Garzik 1298c6fd2807SJeff Garzik /* turn IRQ back on */ 1299c6fd2807SJeff Garzik writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); 1300c6fd2807SJeff Garzik } 1301c6fd2807SJeff Garzik 1302c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1303c6fd2807SJeff Garzik { 13040d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1305c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1306c6fd2807SJeff Garzik 1307c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1308c6fd2807SJeff Garzik /* restart engine */ 1309c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 1310c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 1311c6fd2807SJeff Garzik } 1312c6fd2807SJeff Garzik 1313c6fd2807SJeff Garzik /* perform recovery */ 13144aeb0e32STejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, 1315c6fd2807SJeff Garzik ahci_postreset); 1316c6fd2807SJeff Garzik } 1317c6fd2807SJeff Garzik 1318ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap) 1319ad616ffbSTejun Heo { 13200d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1321ad616ffbSTejun Heo void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1322ad616ffbSTejun Heo 1323ad616ffbSTejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1324ad616ffbSTejun Heo /* restart engine */ 1325ad616ffbSTejun Heo ahci_stop_engine(port_mmio); 1326ad616ffbSTejun Heo ahci_start_engine(port_mmio); 1327ad616ffbSTejun Heo } 1328ad616ffbSTejun Heo 1329ad616ffbSTejun Heo /* perform recovery */ 1330ad616ffbSTejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, 1331ad616ffbSTejun Heo ahci_postreset); 1332ad616ffbSTejun Heo } 1333ad616ffbSTejun Heo 1334c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1335c6fd2807SJeff Garzik { 1336c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 13370d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1338c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1339c6fd2807SJeff Garzik 1340c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_FAILED) 1341c6fd2807SJeff Garzik qc->err_mask |= AC_ERR_OTHER; 1342c6fd2807SJeff Garzik 1343c6fd2807SJeff Garzik if (qc->err_mask) { 1344c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1345c6fd2807SJeff Garzik ahci_stop_engine(port_mmio); 1346c6fd2807SJeff Garzik ahci_start_engine(port_mmio); 1347c6fd2807SJeff Garzik } 1348c6fd2807SJeff Garzik } 1349c6fd2807SJeff Garzik 1350*438ac6d5STejun Heo #ifdef CONFIG_PM 1351c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1352c6fd2807SJeff Garzik { 1353cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1354c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 13550d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1356c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1357c6fd2807SJeff Garzik const char *emsg = NULL; 1358c6fd2807SJeff Garzik int rc; 1359c6fd2807SJeff Garzik 1360c6fd2807SJeff Garzik rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 13618e16f941STejun Heo if (rc == 0) 13628e16f941STejun Heo ahci_power_down(port_mmio, hpriv->cap); 13638e16f941STejun Heo else { 1364c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1365c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, 1366c6fd2807SJeff Garzik pp->cmd_slot_dma, pp->rx_fis_dma); 1367c6fd2807SJeff Garzik } 1368c6fd2807SJeff Garzik 1369c6fd2807SJeff Garzik return rc; 1370c6fd2807SJeff Garzik } 1371c6fd2807SJeff Garzik 1372c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap) 1373c6fd2807SJeff Garzik { 1374c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1375cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 13760d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1377c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1378c6fd2807SJeff Garzik 13798e16f941STejun Heo ahci_power_up(port_mmio, hpriv->cap); 1380c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); 1381c6fd2807SJeff Garzik 1382c6fd2807SJeff Garzik return 0; 1383c6fd2807SJeff Garzik } 1384c6fd2807SJeff Garzik 1385c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1386c6fd2807SJeff Garzik { 1387cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 13880d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1389c6fd2807SJeff Garzik u32 ctl; 1390c6fd2807SJeff Garzik 1391c6fd2807SJeff Garzik if (mesg.event == PM_EVENT_SUSPEND) { 1392c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1393c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1394c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1395c6fd2807SJeff Garzik */ 1396c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1397c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1398c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1399c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1400c6fd2807SJeff Garzik } 1401c6fd2807SJeff Garzik 1402c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1403c6fd2807SJeff Garzik } 1404c6fd2807SJeff Garzik 1405c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1406c6fd2807SJeff Garzik { 1407cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1408cca3974eSJeff Garzik struct ahci_host_priv *hpriv = host->private_data; 14090d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1410c6fd2807SJeff Garzik int rc; 1411c6fd2807SJeff Garzik 1412553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 1413553c4aa6STejun Heo if (rc) 1414553c4aa6STejun Heo return rc; 1415c6fd2807SJeff Garzik 1416c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 1417c6fd2807SJeff Garzik rc = ahci_reset_controller(mmio, pdev); 1418c6fd2807SJeff Garzik if (rc) 1419c6fd2807SJeff Garzik return rc; 1420c6fd2807SJeff Garzik 1421648a88beSTejun Heo ahci_init_controller(mmio, pdev, host->n_ports, 1422648a88beSTejun Heo host->ports[0]->flags, hpriv); 1423c6fd2807SJeff Garzik } 1424c6fd2807SJeff Garzik 1425cca3974eSJeff Garzik ata_host_resume(host); 1426c6fd2807SJeff Garzik 1427c6fd2807SJeff Garzik return 0; 1428c6fd2807SJeff Garzik } 1429*438ac6d5STejun Heo #endif 1430c6fd2807SJeff Garzik 1431c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1432c6fd2807SJeff Garzik { 1433cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1434cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1435c6fd2807SJeff Garzik struct ahci_port_priv *pp; 14360d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1437c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1438c6fd2807SJeff Garzik void *mem; 1439c6fd2807SJeff Garzik dma_addr_t mem_dma; 1440c6fd2807SJeff Garzik int rc; 1441c6fd2807SJeff Garzik 144224dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 1443c6fd2807SJeff Garzik if (!pp) 1444c6fd2807SJeff Garzik return -ENOMEM; 1445c6fd2807SJeff Garzik 1446c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 144724dc5f33STejun Heo if (rc) 1448c6fd2807SJeff Garzik return rc; 1449c6fd2807SJeff Garzik 145024dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 145124dc5f33STejun Heo GFP_KERNEL); 145224dc5f33STejun Heo if (!mem) 1453c6fd2807SJeff Garzik return -ENOMEM; 1454c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1455c6fd2807SJeff Garzik 1456c6fd2807SJeff Garzik /* 1457c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1458c6fd2807SJeff Garzik * 32 bytes each in size 1459c6fd2807SJeff Garzik */ 1460c6fd2807SJeff Garzik pp->cmd_slot = mem; 1461c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 1462c6fd2807SJeff Garzik 1463c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 1464c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 1465c6fd2807SJeff Garzik 1466c6fd2807SJeff Garzik /* 1467c6fd2807SJeff Garzik * Second item: Received-FIS area 1468c6fd2807SJeff Garzik */ 1469c6fd2807SJeff Garzik pp->rx_fis = mem; 1470c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 1471c6fd2807SJeff Garzik 1472c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 1473c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 1474c6fd2807SJeff Garzik 1475c6fd2807SJeff Garzik /* 1476c6fd2807SJeff Garzik * Third item: data area for storing a single command 1477c6fd2807SJeff Garzik * and its scatter-gather table 1478c6fd2807SJeff Garzik */ 1479c6fd2807SJeff Garzik pp->cmd_tbl = mem; 1480c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 1481c6fd2807SJeff Garzik 1482c6fd2807SJeff Garzik ap->private_data = pp; 1483c6fd2807SJeff Garzik 14848e16f941STejun Heo /* power up port */ 14858e16f941STejun Heo ahci_power_up(port_mmio, hpriv->cap); 14868e16f941STejun Heo 1487c6fd2807SJeff Garzik /* initialize port */ 1488c6fd2807SJeff Garzik ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma); 1489c6fd2807SJeff Garzik 1490c6fd2807SJeff Garzik return 0; 1491c6fd2807SJeff Garzik } 1492c6fd2807SJeff Garzik 1493c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 1494c6fd2807SJeff Garzik { 1495cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 14960d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1497c6fd2807SJeff Garzik void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1498c6fd2807SJeff Garzik const char *emsg = NULL; 1499c6fd2807SJeff Garzik int rc; 1500c6fd2807SJeff Garzik 1501c6fd2807SJeff Garzik /* de-initialize port */ 1502c6fd2807SJeff Garzik rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); 1503c6fd2807SJeff Garzik if (rc) 1504c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 1505c6fd2807SJeff Garzik } 1506c6fd2807SJeff Garzik 15070d5ff566STejun Heo static void ahci_setup_port(struct ata_ioports *port, void __iomem *base, 1508c6fd2807SJeff Garzik unsigned int port_idx) 1509c6fd2807SJeff Garzik { 1510c6fd2807SJeff Garzik VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); 15110d5ff566STejun Heo base = ahci_port_base(base, port_idx); 1512c6fd2807SJeff Garzik VPRINTK("base now==0x%lx\n", base); 1513c6fd2807SJeff Garzik 1514c6fd2807SJeff Garzik port->cmd_addr = base; 1515c6fd2807SJeff Garzik port->scr_addr = base + PORT_SCR; 1516c6fd2807SJeff Garzik 1517c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1518c6fd2807SJeff Garzik } 1519c6fd2807SJeff Garzik 1520c6fd2807SJeff Garzik static int ahci_host_init(struct ata_probe_ent *probe_ent) 1521c6fd2807SJeff Garzik { 1522c6fd2807SJeff Garzik struct ahci_host_priv *hpriv = probe_ent->private_data; 1523c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(probe_ent->dev); 15240d5ff566STejun Heo void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; 1525648a88beSTejun Heo unsigned int i, cap_n_ports, using_dac; 1526c6fd2807SJeff Garzik int rc; 1527c6fd2807SJeff Garzik 1528c6fd2807SJeff Garzik rc = ahci_reset_controller(mmio, pdev); 1529c6fd2807SJeff Garzik if (rc) 1530c6fd2807SJeff Garzik return rc; 1531c6fd2807SJeff Garzik 1532c6fd2807SJeff Garzik hpriv->cap = readl(mmio + HOST_CAP); 1533c6fd2807SJeff Garzik hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); 1534648a88beSTejun Heo cap_n_ports = ahci_nr_ports(hpriv->cap); 1535c6fd2807SJeff Garzik 1536c6fd2807SJeff Garzik VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", 1537648a88beSTejun Heo hpriv->cap, hpriv->port_map, cap_n_ports); 1538648a88beSTejun Heo 1539648a88beSTejun Heo if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) { 1540648a88beSTejun Heo unsigned int n_ports = cap_n_ports; 1541648a88beSTejun Heo u32 port_map = hpriv->port_map; 1542648a88beSTejun Heo int max_port = 0; 1543648a88beSTejun Heo 1544648a88beSTejun Heo for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { 1545648a88beSTejun Heo if (port_map & (1 << i)) { 1546648a88beSTejun Heo n_ports--; 1547648a88beSTejun Heo port_map &= ~(1 << i); 1548648a88beSTejun Heo max_port = i; 1549648a88beSTejun Heo } else 1550648a88beSTejun Heo probe_ent->dummy_port_mask |= 1 << i; 1551648a88beSTejun Heo } 1552648a88beSTejun Heo 1553648a88beSTejun Heo if (n_ports || port_map) 1554648a88beSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 1555648a88beSTejun Heo "nr_ports (%u) and implemented port map " 1556648a88beSTejun Heo "(0x%x) don't match\n", 1557648a88beSTejun Heo cap_n_ports, hpriv->port_map); 1558648a88beSTejun Heo 1559648a88beSTejun Heo probe_ent->n_ports = max_port + 1; 1560648a88beSTejun Heo } else 1561648a88beSTejun Heo probe_ent->n_ports = cap_n_ports; 1562c6fd2807SJeff Garzik 1563c6fd2807SJeff Garzik using_dac = hpriv->cap & HOST_CAP_64; 1564c6fd2807SJeff Garzik if (using_dac && 1565c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 1566c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 1567c6fd2807SJeff Garzik if (rc) { 1568c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1569c6fd2807SJeff Garzik if (rc) { 1570c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1571c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 1572c6fd2807SJeff Garzik return rc; 1573c6fd2807SJeff Garzik } 1574c6fd2807SJeff Garzik } 1575c6fd2807SJeff Garzik } else { 1576c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 1577c6fd2807SJeff Garzik if (rc) { 1578c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1579c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 1580c6fd2807SJeff Garzik return rc; 1581c6fd2807SJeff Garzik } 1582c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1583c6fd2807SJeff Garzik if (rc) { 1584c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1585c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 1586c6fd2807SJeff Garzik return rc; 1587c6fd2807SJeff Garzik } 1588c6fd2807SJeff Garzik } 1589c6fd2807SJeff Garzik 1590c6fd2807SJeff Garzik for (i = 0; i < probe_ent->n_ports; i++) 15910d5ff566STejun Heo ahci_setup_port(&probe_ent->port[i], mmio, i); 1592c6fd2807SJeff Garzik 1593648a88beSTejun Heo ahci_init_controller(mmio, pdev, probe_ent->n_ports, 1594648a88beSTejun Heo probe_ent->port_flags, hpriv); 1595c6fd2807SJeff Garzik 1596c6fd2807SJeff Garzik pci_set_master(pdev); 1597c6fd2807SJeff Garzik 1598c6fd2807SJeff Garzik return 0; 1599c6fd2807SJeff Garzik } 1600c6fd2807SJeff Garzik 1601c6fd2807SJeff Garzik static void ahci_print_info(struct ata_probe_ent *probe_ent) 1602c6fd2807SJeff Garzik { 1603c6fd2807SJeff Garzik struct ahci_host_priv *hpriv = probe_ent->private_data; 1604c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(probe_ent->dev); 16050d5ff566STejun Heo void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; 1606c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 1607c6fd2807SJeff Garzik const char *speed_s; 1608c6fd2807SJeff Garzik u16 cc; 1609c6fd2807SJeff Garzik const char *scc_s; 1610c6fd2807SJeff Garzik 1611c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 1612c6fd2807SJeff Garzik cap = hpriv->cap; 1613c6fd2807SJeff Garzik impl = hpriv->port_map; 1614c6fd2807SJeff Garzik 1615c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 1616c6fd2807SJeff Garzik if (speed == 1) 1617c6fd2807SJeff Garzik speed_s = "1.5"; 1618c6fd2807SJeff Garzik else if (speed == 2) 1619c6fd2807SJeff Garzik speed_s = "3"; 1620c6fd2807SJeff Garzik else 1621c6fd2807SJeff Garzik speed_s = "?"; 1622c6fd2807SJeff Garzik 1623c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 1624c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 1625c6fd2807SJeff Garzik scc_s = "IDE"; 1626c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 1627c6fd2807SJeff Garzik scc_s = "SATA"; 1628c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 1629c6fd2807SJeff Garzik scc_s = "RAID"; 1630c6fd2807SJeff Garzik else 1631c6fd2807SJeff Garzik scc_s = "unknown"; 1632c6fd2807SJeff Garzik 1633c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1634c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 1635c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 1636c6fd2807SJeff Garzik , 1637c6fd2807SJeff Garzik 1638c6fd2807SJeff Garzik (vers >> 24) & 0xff, 1639c6fd2807SJeff Garzik (vers >> 16) & 0xff, 1640c6fd2807SJeff Garzik (vers >> 8) & 0xff, 1641c6fd2807SJeff Garzik vers & 0xff, 1642c6fd2807SJeff Garzik 1643c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 1644c6fd2807SJeff Garzik (cap & 0x1f) + 1, 1645c6fd2807SJeff Garzik speed_s, 1646c6fd2807SJeff Garzik impl, 1647c6fd2807SJeff Garzik scc_s); 1648c6fd2807SJeff Garzik 1649c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1650c6fd2807SJeff Garzik "flags: " 1651c6fd2807SJeff Garzik "%s%s%s%s%s%s" 1652c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 1653c6fd2807SJeff Garzik , 1654c6fd2807SJeff Garzik 1655c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 1656c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 1657c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 1658c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 1659c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 1660c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 1661c6fd2807SJeff Garzik 1662c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 1663c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 1664c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 1665c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 1666c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 1667c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 1668c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 1669c6fd2807SJeff Garzik ); 1670c6fd2807SJeff Garzik } 1671c6fd2807SJeff Garzik 1672c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 1673c6fd2807SJeff Garzik { 1674c6fd2807SJeff Garzik static int printed_version; 167524dc5f33STejun Heo unsigned int board_idx = (unsigned int) ent->driver_data; 167624dc5f33STejun Heo struct device *dev = &pdev->dev; 167724dc5f33STejun Heo struct ata_probe_ent *probe_ent; 1678c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 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 168824dc5f33STejun Heo rc = pcim_enable_device(pdev); 1689c6fd2807SJeff Garzik if (rc) 1690c6fd2807SJeff Garzik return rc; 1691c6fd2807SJeff Garzik 16920d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 16930d5ff566STejun Heo if (rc == -EBUSY) 169424dc5f33STejun Heo pcim_pin_device(pdev); 16950d5ff566STejun Heo if (rc) 169624dc5f33STejun Heo return rc; 1697c6fd2807SJeff Garzik 169824dc5f33STejun Heo if (pci_enable_msi(pdev)) 1699c6fd2807SJeff Garzik pci_intx(pdev, 1); 1700c6fd2807SJeff Garzik 170124dc5f33STejun Heo probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); 170224dc5f33STejun Heo if (probe_ent == NULL) 170324dc5f33STejun Heo return -ENOMEM; 1704c6fd2807SJeff Garzik 1705c6fd2807SJeff Garzik probe_ent->dev = pci_dev_to_dev(pdev); 1706c6fd2807SJeff Garzik INIT_LIST_HEAD(&probe_ent->node); 1707c6fd2807SJeff Garzik 170824dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 170924dc5f33STejun Heo if (!hpriv) 171024dc5f33STejun Heo return -ENOMEM; 1711c6fd2807SJeff Garzik 1712c6fd2807SJeff Garzik probe_ent->sht = ahci_port_info[board_idx].sht; 1713cca3974eSJeff Garzik probe_ent->port_flags = ahci_port_info[board_idx].flags; 1714c6fd2807SJeff Garzik probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask; 1715c6fd2807SJeff Garzik probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask; 1716c6fd2807SJeff Garzik probe_ent->port_ops = ahci_port_info[board_idx].port_ops; 1717c6fd2807SJeff Garzik 1718c6fd2807SJeff Garzik probe_ent->irq = pdev->irq; 1719c6fd2807SJeff Garzik probe_ent->irq_flags = IRQF_SHARED; 17200d5ff566STejun Heo probe_ent->iomap = pcim_iomap_table(pdev); 1721c6fd2807SJeff Garzik probe_ent->private_data = hpriv; 1722c6fd2807SJeff Garzik 1723c6fd2807SJeff Garzik /* initialize adapter */ 1724c6fd2807SJeff Garzik rc = ahci_host_init(probe_ent); 1725c6fd2807SJeff Garzik if (rc) 172624dc5f33STejun Heo return rc; 1727c6fd2807SJeff Garzik 1728cca3974eSJeff Garzik if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) && 1729c6fd2807SJeff Garzik (hpriv->cap & HOST_CAP_NCQ)) 1730cca3974eSJeff Garzik probe_ent->port_flags |= ATA_FLAG_NCQ; 1731c6fd2807SJeff Garzik 1732c6fd2807SJeff Garzik ahci_print_info(probe_ent); 1733c6fd2807SJeff Garzik 173424dc5f33STejun Heo if (!ata_device_add(probe_ent)) 173524dc5f33STejun Heo return -ENODEV; 1736c6fd2807SJeff Garzik 173724dc5f33STejun Heo devm_kfree(dev, probe_ent); 1738c6fd2807SJeff Garzik return 0; 1739c6fd2807SJeff Garzik } 1740c6fd2807SJeff Garzik 1741c6fd2807SJeff Garzik static int __init ahci_init(void) 1742c6fd2807SJeff Garzik { 1743c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 1744c6fd2807SJeff Garzik } 1745c6fd2807SJeff Garzik 1746c6fd2807SJeff Garzik static void __exit ahci_exit(void) 1747c6fd2807SJeff Garzik { 1748c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 1749c6fd2807SJeff Garzik } 1750c6fd2807SJeff Garzik 1751c6fd2807SJeff Garzik 1752c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 1753c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 1754c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 1755c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 1756c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 1757c6fd2807SJeff Garzik 1758c6fd2807SJeff Garzik module_init(ahci_init); 1759c6fd2807SJeff Garzik module_exit(ahci_exit); 1760