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, 8355a61604SConke Hu board_ahci_sb600 = 4, 84c6fd2807SJeff Garzik 85c6fd2807SJeff Garzik /* global controller registers */ 86c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 87c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 88c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 89c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 90c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 91c6fd2807SJeff Garzik 92c6fd2807SJeff Garzik /* HOST_CTL bits */ 93c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 94c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 95c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 96c6fd2807SJeff Garzik 97c6fd2807SJeff Garzik /* HOST_CAP bits */ 98c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 99c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 100c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 101c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 102c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 103c6fd2807SJeff Garzik 104c6fd2807SJeff Garzik /* registers for each SATA port */ 105c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 106c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 107c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 108c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 109c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 110c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 111c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 112c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 113c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 114c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 115c6fd2807SJeff Garzik PORT_SCR = 0x28, /* SATA phy register block */ 116c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 117c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 118c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 119c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 120c6fd2807SJeff Garzik 121c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 122c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 123c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 124c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 125c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 126c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 127c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 128c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 129c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 130c6fd2807SJeff Garzik 131c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 132c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 133c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 134c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 135c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 136c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 137c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 138c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 139c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 140c6fd2807SJeff Garzik 141c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 142c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 143c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 144c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 145c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS, 146c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 147c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 148c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 149c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 150c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 151c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 152c6fd2807SJeff Garzik 153c6fd2807SJeff Garzik /* PORT_CMD bits */ 154c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 155c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 156c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 157c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 158c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 159c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 160c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 161c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 162c6fd2807SJeff Garzik 163c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 164c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 165c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 166c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 167c6fd2807SJeff Garzik 168c6fd2807SJeff Garzik /* ap->flags bits */ 1694aeb0e32STejun Heo AHCI_FLAG_NO_NCQ = (1 << 24), 1704aeb0e32STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ 171648a88beSTejun Heo AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ 17255a61604SConke Hu AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ 173c6fd2807SJeff Garzik }; 174c6fd2807SJeff Garzik 175c6fd2807SJeff Garzik struct ahci_cmd_hdr { 176c6fd2807SJeff Garzik u32 opts; 177c6fd2807SJeff Garzik u32 status; 178c6fd2807SJeff Garzik u32 tbl_addr; 179c6fd2807SJeff Garzik u32 tbl_addr_hi; 180c6fd2807SJeff Garzik u32 reserved[4]; 181c6fd2807SJeff Garzik }; 182c6fd2807SJeff Garzik 183c6fd2807SJeff Garzik struct ahci_sg { 184c6fd2807SJeff Garzik u32 addr; 185c6fd2807SJeff Garzik u32 addr_hi; 186c6fd2807SJeff Garzik u32 reserved; 187c6fd2807SJeff Garzik u32 flags_size; 188c6fd2807SJeff Garzik }; 189c6fd2807SJeff Garzik 190c6fd2807SJeff Garzik struct ahci_host_priv { 191d447df14STejun Heo u32 cap; /* cap to use */ 192d447df14STejun Heo u32 port_map; /* port map to use */ 193d447df14STejun Heo u32 saved_cap; /* saved initial cap */ 194d447df14STejun Heo u32 saved_port_map; /* saved initial port_map */ 195c6fd2807SJeff Garzik }; 196c6fd2807SJeff Garzik 197c6fd2807SJeff Garzik struct ahci_port_priv { 198c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 199c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 200c6fd2807SJeff Garzik void *cmd_tbl; 201c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 202c6fd2807SJeff Garzik void *rx_fis; 203c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2040291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2050291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2060291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 207afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 208c6fd2807SJeff Garzik }; 209c6fd2807SJeff Garzik 210c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); 211c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 212c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 213c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 214c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap); 215c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 216c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 217c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 218c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 219c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap); 220c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 221c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 222c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 223ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap); 224c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 225438ac6d5STejun Heo #ifdef CONFIG_PM 226c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 227c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 228c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 229c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 230438ac6d5STejun Heo #endif 231c6fd2807SJeff Garzik 232c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 233c6fd2807SJeff Garzik .module = THIS_MODULE, 234c6fd2807SJeff Garzik .name = DRV_NAME, 235c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 236c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 237c6fd2807SJeff Garzik .change_queue_depth = ata_scsi_change_queue_depth, 238c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 239c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 240c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 241c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 242c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 243c6fd2807SJeff Garzik .use_clustering = AHCI_USE_CLUSTERING, 244c6fd2807SJeff Garzik .proc_name = DRV_NAME, 245c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 246c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 247c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 248c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 249438ac6d5STejun Heo #ifdef CONFIG_PM 250c6fd2807SJeff Garzik .suspend = ata_scsi_device_suspend, 251c6fd2807SJeff Garzik .resume = ata_scsi_device_resume, 252438ac6d5STejun Heo #endif 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_clear = ahci_irq_clear, 268246ce3b6SAkira Iguchi .irq_on = ata_dummy_irq_on, 269246ce3b6SAkira Iguchi .irq_ack = ata_dummy_irq_ack, 270c6fd2807SJeff Garzik 271c6fd2807SJeff Garzik .scr_read = ahci_scr_read, 272c6fd2807SJeff Garzik .scr_write = ahci_scr_write, 273c6fd2807SJeff Garzik 274c6fd2807SJeff Garzik .freeze = ahci_freeze, 275c6fd2807SJeff Garzik .thaw = ahci_thaw, 276c6fd2807SJeff Garzik 277c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 278c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 279c6fd2807SJeff Garzik 280438ac6d5STejun Heo #ifdef CONFIG_PM 281c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 282c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 283438ac6d5STejun Heo #endif 284c6fd2807SJeff Garzik 285c6fd2807SJeff Garzik .port_start = ahci_port_start, 286c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 287c6fd2807SJeff Garzik }; 288c6fd2807SJeff Garzik 289ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = { 290ad616ffbSTejun Heo .port_disable = ata_port_disable, 291ad616ffbSTejun Heo 292ad616ffbSTejun Heo .check_status = ahci_check_status, 293ad616ffbSTejun Heo .check_altstatus = ahci_check_status, 294ad616ffbSTejun Heo .dev_select = ata_noop_dev_select, 295ad616ffbSTejun Heo 296ad616ffbSTejun Heo .tf_read = ahci_tf_read, 297ad616ffbSTejun Heo 298ad616ffbSTejun Heo .qc_prep = ahci_qc_prep, 299ad616ffbSTejun Heo .qc_issue = ahci_qc_issue, 300ad616ffbSTejun Heo 301ad616ffbSTejun Heo .irq_clear = ahci_irq_clear, 302246ce3b6SAkira Iguchi .irq_on = ata_dummy_irq_on, 303246ce3b6SAkira Iguchi .irq_ack = ata_dummy_irq_ack, 304ad616ffbSTejun Heo 305ad616ffbSTejun Heo .scr_read = ahci_scr_read, 306ad616ffbSTejun Heo .scr_write = ahci_scr_write, 307ad616ffbSTejun Heo 308ad616ffbSTejun Heo .freeze = ahci_freeze, 309ad616ffbSTejun Heo .thaw = ahci_thaw, 310ad616ffbSTejun Heo 311ad616ffbSTejun Heo .error_handler = ahci_vt8251_error_handler, 312ad616ffbSTejun Heo .post_internal_cmd = ahci_post_internal_cmd, 313ad616ffbSTejun Heo 314438ac6d5STejun Heo #ifdef CONFIG_PM 315ad616ffbSTejun Heo .port_suspend = ahci_port_suspend, 316ad616ffbSTejun Heo .port_resume = ahci_port_resume, 317438ac6d5STejun Heo #endif 318ad616ffbSTejun Heo 319ad616ffbSTejun Heo .port_start = ahci_port_start, 320ad616ffbSTejun Heo .port_stop = ahci_port_stop, 321ad616ffbSTejun Heo }; 322ad616ffbSTejun Heo 323c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 324c6fd2807SJeff Garzik /* board_ahci */ 325c6fd2807SJeff Garzik { 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 .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 336648a88beSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 337648a88beSTejun Heo ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI, 338648a88beSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 339648a88beSTejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 340648a88beSTejun Heo .port_ops = &ahci_ops, 341648a88beSTejun Heo }, 342c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 343c6fd2807SJeff Garzik { 344cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 345c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 346ad616ffbSTejun Heo ATA_FLAG_SKIP_D2H_BSY | 347ad616ffbSTejun Heo ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, 348c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 349c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 350ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 351c6fd2807SJeff Garzik }, 35241669553STejun Heo /* board_ahci_ign_iferr */ 35341669553STejun Heo { 35441669553STejun Heo .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 35541669553STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 35641669553STejun Heo ATA_FLAG_SKIP_D2H_BSY | 35741669553STejun Heo AHCI_FLAG_IGN_IRQ_IF_ERR, 35841669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 35941669553STejun Heo .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 36041669553STejun Heo .port_ops = &ahci_ops, 36141669553STejun Heo }, 36255a61604SConke Hu /* board_ahci_sb600 */ 36355a61604SConke Hu { 36455a61604SConke Hu .sht = &ahci_sht, 36555a61604SConke Hu .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 36655a61604SConke Hu ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 36755a61604SConke Hu ATA_FLAG_SKIP_D2H_BSY | 36855a61604SConke Hu AHCI_FLAG_IGN_SERR_INTERNAL, 36955a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 37055a61604SConke Hu .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 37155a61604SConke Hu .port_ops = &ahci_ops, 37255a61604SConke Hu }, 37355a61604SConke Hu 374c6fd2807SJeff Garzik }; 375c6fd2807SJeff Garzik 376c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 377c6fd2807SJeff Garzik /* Intel */ 37854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 37954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 38054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 38154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 38254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 38382490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 38454bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 38554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 38654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 38754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 388648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ 389648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ 390648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ 391648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ 392648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ 393648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ 394648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ 395648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ 396648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ 397648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ 398648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ 399648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ 400648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ 4018af12cdbSJason Gaston { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ 402648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ 403648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ 404648a88beSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ 405c6fd2807SJeff Garzik 406e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 407e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 408e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 409c6fd2807SJeff Garzik 410c6fd2807SJeff Garzik /* ATI */ 411c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 412c6fd2807SJeff Garzik 413c6fd2807SJeff Garzik /* VIA */ 41454bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 415bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 416c6fd2807SJeff Garzik 417c6fd2807SJeff Garzik /* NVIDIA */ 41854bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ 41954bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ 42054bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ 42154bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ 4226fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ 4236fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ 4246fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ 4256fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ 4266fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 4276fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 4286fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 4296fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 430895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 431895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 432895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 433895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 434895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 435895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 436895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 437895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 438c6fd2807SJeff Garzik 439c6fd2807SJeff Garzik /* SiS */ 44054bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 44154bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 44254bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 443c6fd2807SJeff Garzik 444415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 445415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 446c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 447415ae2b5SJeff Garzik 448c6fd2807SJeff Garzik { } /* terminate list */ 449c6fd2807SJeff Garzik }; 450c6fd2807SJeff Garzik 451c6fd2807SJeff Garzik 452c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 453c6fd2807SJeff Garzik .name = DRV_NAME, 454c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 455c6fd2807SJeff Garzik .probe = ahci_init_one, 45624dc5f33STejun Heo .remove = ata_pci_remove_one, 457438ac6d5STejun Heo #ifdef CONFIG_PM 458c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 459c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 460438ac6d5STejun Heo #endif 461c6fd2807SJeff Garzik }; 462c6fd2807SJeff Garzik 463c6fd2807SJeff Garzik 46498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 46598fa4b60STejun Heo { 46698fa4b60STejun Heo return (cap & 0x1f) + 1; 46798fa4b60STejun Heo } 46898fa4b60STejun Heo 469*4447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 470c6fd2807SJeff Garzik { 471*4447d351STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 472*4447d351STejun Heo 473*4447d351STejun Heo return mmio + 0x100 + (ap->port_no * 0x80); 474c6fd2807SJeff Garzik } 475c6fd2807SJeff Garzik 476d447df14STejun Heo /** 477d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 478*4447d351STejun Heo * @pdev: target PCI device 479*4447d351STejun Heo * @pi: associated ATA port info 480*4447d351STejun Heo * @hpriv: host private area to store config values 481d447df14STejun Heo * 482d447df14STejun Heo * Some registers containing configuration info might be setup by 483d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 484d447df14STejun Heo * initial values of those registers into @hpriv such that they 485d447df14STejun Heo * can be restored after controller reset. 486d447df14STejun Heo * 487d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 488d447df14STejun Heo * 489d447df14STejun Heo * LOCKING: 490d447df14STejun Heo * None. 491d447df14STejun Heo */ 492*4447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 493*4447d351STejun Heo const struct ata_port_info *pi, 494*4447d351STejun Heo struct ahci_host_priv *hpriv) 495d447df14STejun Heo { 496*4447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 497d447df14STejun Heo u32 cap, port_map; 49817199b18STejun Heo int i; 499d447df14STejun Heo 500d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 501d447df14STejun Heo * reset. Values without are used for driver operation. 502d447df14STejun Heo */ 503d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 504d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 505d447df14STejun Heo 506d447df14STejun Heo /* fixup zero port_map */ 507d447df14STejun Heo if (!port_map) { 508d447df14STejun Heo port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1; 509*4447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 510d447df14STejun Heo "PORTS_IMPL is zero, forcing 0x%x\n", port_map); 511d447df14STejun Heo 512d447df14STejun Heo /* write the fixed up value to the PI register */ 513d447df14STejun Heo hpriv->saved_port_map = port_map; 514d447df14STejun Heo } 515d447df14STejun Heo 51617199b18STejun Heo /* cross check port_map and cap.n_ports */ 517*4447d351STejun Heo if (pi->flags & AHCI_FLAG_HONOR_PI) { 51817199b18STejun Heo u32 tmp_port_map = port_map; 51917199b18STejun Heo int n_ports = ahci_nr_ports(cap); 52017199b18STejun Heo 52117199b18STejun Heo for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { 52217199b18STejun Heo if (tmp_port_map & (1 << i)) { 52317199b18STejun Heo n_ports--; 52417199b18STejun Heo tmp_port_map &= ~(1 << i); 52517199b18STejun Heo } 52617199b18STejun Heo } 52717199b18STejun Heo 52817199b18STejun Heo /* Whine if inconsistent. No need to update cap. 52917199b18STejun Heo * port_map is used to determine number of ports. 53017199b18STejun Heo */ 53117199b18STejun Heo if (n_ports || tmp_port_map) 532*4447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 53317199b18STejun Heo "nr_ports (%u) and implemented port map " 53417199b18STejun Heo "(0x%x) don't match\n", 53517199b18STejun Heo ahci_nr_ports(cap), port_map); 53617199b18STejun Heo } else { 53717199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 53817199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 53917199b18STejun Heo } 54017199b18STejun Heo 541d447df14STejun Heo /* record values to use during operation */ 542d447df14STejun Heo hpriv->cap = cap; 543d447df14STejun Heo hpriv->port_map = port_map; 544d447df14STejun Heo } 545d447df14STejun Heo 546d447df14STejun Heo /** 547d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 548*4447d351STejun Heo * @host: target ATA host 549d447df14STejun Heo * 550d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 551d447df14STejun Heo * 552d447df14STejun Heo * LOCKING: 553d447df14STejun Heo * None. 554d447df14STejun Heo */ 555*4447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 556d447df14STejun Heo { 557*4447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 558*4447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 559*4447d351STejun Heo 560d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 561d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 562d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 563d447df14STejun Heo } 564d447df14STejun Heo 565c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) 566c6fd2807SJeff Garzik { 567c6fd2807SJeff Garzik unsigned int sc_reg; 568c6fd2807SJeff Garzik 569c6fd2807SJeff Garzik switch (sc_reg_in) { 570c6fd2807SJeff Garzik case SCR_STATUS: sc_reg = 0; break; 571c6fd2807SJeff Garzik case SCR_CONTROL: sc_reg = 1; break; 572c6fd2807SJeff Garzik case SCR_ERROR: sc_reg = 2; break; 573c6fd2807SJeff Garzik case SCR_ACTIVE: sc_reg = 3; break; 574c6fd2807SJeff Garzik default: 575c6fd2807SJeff Garzik return 0xffffffffU; 576c6fd2807SJeff Garzik } 577c6fd2807SJeff Garzik 5780d5ff566STejun Heo return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); 579c6fd2807SJeff Garzik } 580c6fd2807SJeff Garzik 581c6fd2807SJeff Garzik 582c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, 583c6fd2807SJeff Garzik u32 val) 584c6fd2807SJeff Garzik { 585c6fd2807SJeff Garzik unsigned int sc_reg; 586c6fd2807SJeff Garzik 587c6fd2807SJeff Garzik switch (sc_reg_in) { 588c6fd2807SJeff Garzik case SCR_STATUS: sc_reg = 0; break; 589c6fd2807SJeff Garzik case SCR_CONTROL: sc_reg = 1; break; 590c6fd2807SJeff Garzik case SCR_ERROR: sc_reg = 2; break; 591c6fd2807SJeff Garzik case SCR_ACTIVE: sc_reg = 3; break; 592c6fd2807SJeff Garzik default: 593c6fd2807SJeff Garzik return; 594c6fd2807SJeff Garzik } 595c6fd2807SJeff Garzik 5960d5ff566STejun Heo writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); 597c6fd2807SJeff Garzik } 598c6fd2807SJeff Garzik 599*4447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 600c6fd2807SJeff Garzik { 601*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 602c6fd2807SJeff Garzik u32 tmp; 603c6fd2807SJeff Garzik 604c6fd2807SJeff Garzik /* start DMA */ 605c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 606c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 607c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 608c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 609c6fd2807SJeff Garzik } 610c6fd2807SJeff Garzik 611*4447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 612c6fd2807SJeff Garzik { 613*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 614c6fd2807SJeff Garzik u32 tmp; 615c6fd2807SJeff Garzik 616c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 617c6fd2807SJeff Garzik 618c6fd2807SJeff Garzik /* check if the HBA is idle */ 619c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 620c6fd2807SJeff Garzik return 0; 621c6fd2807SJeff Garzik 622c6fd2807SJeff Garzik /* setting HBA to idle */ 623c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 624c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 625c6fd2807SJeff Garzik 626c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 627c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 628c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 629c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 630c6fd2807SJeff Garzik return -EIO; 631c6fd2807SJeff Garzik 632c6fd2807SJeff Garzik return 0; 633c6fd2807SJeff Garzik } 634c6fd2807SJeff Garzik 635*4447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 636c6fd2807SJeff Garzik { 637*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 638*4447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 639*4447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 640c6fd2807SJeff Garzik u32 tmp; 641c6fd2807SJeff Garzik 642c6fd2807SJeff Garzik /* set FIS registers */ 643*4447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 644*4447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 645*4447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 646*4447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 647c6fd2807SJeff Garzik 648*4447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 649*4447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 650*4447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 651*4447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 652c6fd2807SJeff Garzik 653c6fd2807SJeff Garzik /* enable FIS reception */ 654c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 655c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 656c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 657c6fd2807SJeff Garzik 658c6fd2807SJeff Garzik /* flush */ 659c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 660c6fd2807SJeff Garzik } 661c6fd2807SJeff Garzik 662*4447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 663c6fd2807SJeff Garzik { 664*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 665c6fd2807SJeff Garzik u32 tmp; 666c6fd2807SJeff Garzik 667c6fd2807SJeff Garzik /* disable FIS reception */ 668c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 669c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 670c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 671c6fd2807SJeff Garzik 672c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 673c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 674c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 675c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 676c6fd2807SJeff Garzik return -EBUSY; 677c6fd2807SJeff Garzik 678c6fd2807SJeff Garzik return 0; 679c6fd2807SJeff Garzik } 680c6fd2807SJeff Garzik 681*4447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 682c6fd2807SJeff Garzik { 683*4447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 684*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 685c6fd2807SJeff Garzik u32 cmd; 686c6fd2807SJeff Garzik 687c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 688c6fd2807SJeff Garzik 689c6fd2807SJeff Garzik /* spin up device */ 690*4447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 691c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 692c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 693c6fd2807SJeff Garzik } 694c6fd2807SJeff Garzik 695c6fd2807SJeff Garzik /* wake up link */ 696c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 697c6fd2807SJeff Garzik } 698c6fd2807SJeff Garzik 699438ac6d5STejun Heo #ifdef CONFIG_PM 700*4447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 701c6fd2807SJeff Garzik { 702*4447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 703*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 704c6fd2807SJeff Garzik u32 cmd, scontrol; 705c6fd2807SJeff Garzik 706*4447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 70707c53dacSTejun Heo return; 708c6fd2807SJeff Garzik 70907c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 710c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 711c6fd2807SJeff Garzik scontrol &= ~0xf; 712c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 713c6fd2807SJeff Garzik 714c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 71507c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 716c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 717c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 718c6fd2807SJeff Garzik } 719438ac6d5STejun Heo #endif 720c6fd2807SJeff Garzik 721*4447d351STejun Heo static void ahci_init_port(struct ata_port *ap) 722c6fd2807SJeff Garzik { 723c6fd2807SJeff Garzik /* enable FIS reception */ 724*4447d351STejun Heo ahci_start_fis_rx(ap); 725c6fd2807SJeff Garzik 726c6fd2807SJeff Garzik /* enable DMA */ 727*4447d351STejun Heo ahci_start_engine(ap); 728c6fd2807SJeff Garzik } 729c6fd2807SJeff Garzik 730*4447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 731c6fd2807SJeff Garzik { 732c6fd2807SJeff Garzik int rc; 733c6fd2807SJeff Garzik 734c6fd2807SJeff Garzik /* disable DMA */ 735*4447d351STejun Heo rc = ahci_stop_engine(ap); 736c6fd2807SJeff Garzik if (rc) { 737c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 738c6fd2807SJeff Garzik return rc; 739c6fd2807SJeff Garzik } 740c6fd2807SJeff Garzik 741c6fd2807SJeff Garzik /* disable FIS reception */ 742*4447d351STejun Heo rc = ahci_stop_fis_rx(ap); 743c6fd2807SJeff Garzik if (rc) { 744c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 745c6fd2807SJeff Garzik return rc; 746c6fd2807SJeff Garzik } 747c6fd2807SJeff Garzik 748c6fd2807SJeff Garzik return 0; 749c6fd2807SJeff Garzik } 750c6fd2807SJeff Garzik 751*4447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 752c6fd2807SJeff Garzik { 753*4447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 754*4447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 755d447df14STejun Heo u32 tmp; 756c6fd2807SJeff Garzik 757c6fd2807SJeff Garzik /* global controller reset */ 758c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 759c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 760c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 761c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 762c6fd2807SJeff Garzik } 763c6fd2807SJeff Garzik 764c6fd2807SJeff Garzik /* reset must complete within 1 second, or 765c6fd2807SJeff Garzik * the hardware should be considered fried. 766c6fd2807SJeff Garzik */ 767c6fd2807SJeff Garzik ssleep(1); 768c6fd2807SJeff Garzik 769c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 770c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 771*4447d351STejun Heo dev_printk(KERN_ERR, host->dev, 772c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 773c6fd2807SJeff Garzik return -EIO; 774c6fd2807SJeff Garzik } 775c6fd2807SJeff Garzik 77698fa4b60STejun Heo /* turn on AHCI mode */ 777c6fd2807SJeff Garzik writel(HOST_AHCI_EN, mmio + HOST_CTL); 778c6fd2807SJeff Garzik (void) readl(mmio + HOST_CTL); /* flush */ 77998fa4b60STejun Heo 780d447df14STejun Heo /* some registers might be cleared on reset. restore initial values */ 781*4447d351STejun Heo ahci_restore_initial_config(host); 782c6fd2807SJeff Garzik 783c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 784c6fd2807SJeff Garzik u16 tmp16; 785c6fd2807SJeff Garzik 786c6fd2807SJeff Garzik /* configure PCS */ 787c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 788c6fd2807SJeff Garzik tmp16 |= 0xf; 789c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 790c6fd2807SJeff Garzik } 791c6fd2807SJeff Garzik 792c6fd2807SJeff Garzik return 0; 793c6fd2807SJeff Garzik } 794c6fd2807SJeff Garzik 795*4447d351STejun Heo static void ahci_init_controller(struct ata_host *host) 796c6fd2807SJeff Garzik { 797*4447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 798*4447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 799c6fd2807SJeff Garzik int i, rc; 800c6fd2807SJeff Garzik u32 tmp; 801c6fd2807SJeff Garzik 802*4447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 803*4447d351STejun Heo struct ata_port *ap = host->ports[i]; 804*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 805c6fd2807SJeff Garzik const char *emsg = NULL; 806c6fd2807SJeff Garzik 807*4447d351STejun Heo if (ata_port_is_dummy(ap)) 808c6fd2807SJeff Garzik continue; 809c6fd2807SJeff Garzik 810c6fd2807SJeff Garzik /* make sure port is not active */ 811*4447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 812c6fd2807SJeff Garzik if (rc) 813c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 814c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 815c6fd2807SJeff Garzik 816c6fd2807SJeff Garzik /* clear SError */ 817c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 818c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 819c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 820c6fd2807SJeff Garzik 821c6fd2807SJeff Garzik /* clear port IRQ */ 822c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 823c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 824c6fd2807SJeff Garzik if (tmp) 825c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 826c6fd2807SJeff Garzik 827c6fd2807SJeff Garzik writel(1 << i, mmio + HOST_IRQ_STAT); 828c6fd2807SJeff Garzik } 829c6fd2807SJeff Garzik 830c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 831c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 832c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 833c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 834c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 835c6fd2807SJeff Garzik } 836c6fd2807SJeff Garzik 837c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 838c6fd2807SJeff Garzik { 839*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 840c6fd2807SJeff Garzik struct ata_taskfile tf; 841c6fd2807SJeff Garzik u32 tmp; 842c6fd2807SJeff Garzik 843c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 844c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 845c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 846c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 847c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 848c6fd2807SJeff Garzik 849c6fd2807SJeff Garzik return ata_dev_classify(&tf); 850c6fd2807SJeff Garzik } 851c6fd2807SJeff Garzik 852c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 853c6fd2807SJeff Garzik u32 opts) 854c6fd2807SJeff Garzik { 855c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 856c6fd2807SJeff Garzik 857c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 858c6fd2807SJeff Garzik 859c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 860c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 861c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 862c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 863c6fd2807SJeff Garzik } 864c6fd2807SJeff Garzik 865c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap) 866c6fd2807SJeff Garzik { 8670d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 868cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 869c6fd2807SJeff Garzik u32 tmp; 870c6fd2807SJeff Garzik 871c6fd2807SJeff Garzik if (!(hpriv->cap & HOST_CAP_CLO)) 872c6fd2807SJeff Garzik return -EOPNOTSUPP; 873c6fd2807SJeff Garzik 874c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 875c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 876c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 877c6fd2807SJeff Garzik 878c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 879c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 880c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 881c6fd2807SJeff Garzik return -EIO; 882c6fd2807SJeff Garzik 883c6fd2807SJeff Garzik return 0; 884c6fd2807SJeff Garzik } 885c6fd2807SJeff Garzik 886c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class) 887c6fd2807SJeff Garzik { 888c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 889*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 890c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 891c6fd2807SJeff Garzik const char *reason = NULL; 892c6fd2807SJeff Garzik struct ata_taskfile tf; 893c6fd2807SJeff Garzik u32 tmp; 894c6fd2807SJeff Garzik u8 *fis; 895c6fd2807SJeff Garzik int rc; 896c6fd2807SJeff Garzik 897c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 898c6fd2807SJeff Garzik 899c6fd2807SJeff Garzik if (ata_port_offline(ap)) { 900c6fd2807SJeff Garzik DPRINTK("PHY reports no device\n"); 901c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 902c6fd2807SJeff Garzik return 0; 903c6fd2807SJeff Garzik } 904c6fd2807SJeff Garzik 905c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 906*4447d351STejun Heo rc = ahci_stop_engine(ap); 907c6fd2807SJeff Garzik if (rc) { 908c6fd2807SJeff Garzik reason = "failed to stop engine"; 909c6fd2807SJeff Garzik goto fail_restart; 910c6fd2807SJeff Garzik } 911c6fd2807SJeff Garzik 912c6fd2807SJeff Garzik /* check BUSY/DRQ, perform Command List Override if necessary */ 9131244a19cSTejun Heo if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) { 914c6fd2807SJeff Garzik rc = ahci_clo(ap); 915c6fd2807SJeff Garzik 916c6fd2807SJeff Garzik if (rc == -EOPNOTSUPP) { 917c6fd2807SJeff Garzik reason = "port busy but CLO unavailable"; 918c6fd2807SJeff Garzik goto fail_restart; 919c6fd2807SJeff Garzik } else if (rc) { 920c6fd2807SJeff Garzik reason = "port busy but CLO failed"; 921c6fd2807SJeff Garzik goto fail_restart; 922c6fd2807SJeff Garzik } 923c6fd2807SJeff Garzik } 924c6fd2807SJeff Garzik 925c6fd2807SJeff Garzik /* restart engine */ 926*4447d351STejun Heo ahci_start_engine(ap); 927c6fd2807SJeff Garzik 928c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 929c6fd2807SJeff Garzik fis = pp->cmd_tbl; 930c6fd2807SJeff Garzik 931c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 932c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, 933c6fd2807SJeff Garzik cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); 934c6fd2807SJeff Garzik 935c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 936c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 937c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 938c6fd2807SJeff Garzik 939c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 940c6fd2807SJeff Garzik 941c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500); 942c6fd2807SJeff Garzik if (tmp & 0x1) { 943c6fd2807SJeff Garzik rc = -EIO; 944c6fd2807SJeff Garzik reason = "1st FIS failed"; 945c6fd2807SJeff Garzik goto fail; 946c6fd2807SJeff Garzik } 947c6fd2807SJeff Garzik 948c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 949c6fd2807SJeff Garzik msleep(1); 950c6fd2807SJeff Garzik 951c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 952c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, 0, cmd_fis_len); 953c6fd2807SJeff Garzik 954c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 955c6fd2807SJeff Garzik ata_tf_to_fis(&tf, fis, 0); 956c6fd2807SJeff Garzik fis[1] &= ~(1 << 7); /* turn off Command FIS bit */ 957c6fd2807SJeff Garzik 958c6fd2807SJeff Garzik writel(1, port_mmio + PORT_CMD_ISSUE); 959c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 960c6fd2807SJeff Garzik 961c6fd2807SJeff Garzik /* spec mandates ">= 2ms" before checking status. 962c6fd2807SJeff Garzik * We wait 150ms, because that was the magic delay used for 963c6fd2807SJeff Garzik * ATAPI devices in Hale Landis's ATADRVR, for the period of time 964c6fd2807SJeff Garzik * between when the ATA command register is written, and then 965c6fd2807SJeff Garzik * status is checked. Because waiting for "a while" before 966c6fd2807SJeff Garzik * checking status is fine, post SRST, we perform this magic 967c6fd2807SJeff Garzik * delay here as well. 968c6fd2807SJeff Garzik */ 969c6fd2807SJeff Garzik msleep(150); 970c6fd2807SJeff Garzik 971c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 972c6fd2807SJeff Garzik if (ata_port_online(ap)) { 973c6fd2807SJeff Garzik if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { 974c6fd2807SJeff Garzik rc = -EIO; 975c6fd2807SJeff Garzik reason = "device not ready"; 976c6fd2807SJeff Garzik goto fail; 977c6fd2807SJeff Garzik } 978c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 979c6fd2807SJeff Garzik } 980c6fd2807SJeff Garzik 981c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 982c6fd2807SJeff Garzik return 0; 983c6fd2807SJeff Garzik 984c6fd2807SJeff Garzik fail_restart: 985*4447d351STejun Heo ahci_start_engine(ap); 986c6fd2807SJeff Garzik fail: 987c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); 988c6fd2807SJeff Garzik return rc; 989c6fd2807SJeff Garzik } 990c6fd2807SJeff Garzik 991c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class) 992c6fd2807SJeff Garzik { 993c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 994c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 995c6fd2807SJeff Garzik struct ata_taskfile tf; 996c6fd2807SJeff Garzik int rc; 997c6fd2807SJeff Garzik 998c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 999c6fd2807SJeff Garzik 1000*4447d351STejun Heo ahci_stop_engine(ap); 1001c6fd2807SJeff Garzik 1002c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1003c6fd2807SJeff Garzik ata_tf_init(ap->device, &tf); 1004dfd7a3dbSTejun Heo tf.command = 0x80; 1005c6fd2807SJeff Garzik ata_tf_to_fis(&tf, d2h_fis, 0); 1006c6fd2807SJeff Garzik 1007c6fd2807SJeff Garzik rc = sata_std_hardreset(ap, class); 1008c6fd2807SJeff Garzik 1009*4447d351STejun Heo ahci_start_engine(ap); 1010c6fd2807SJeff Garzik 1011c6fd2807SJeff Garzik if (rc == 0 && ata_port_online(ap)) 1012c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1013c6fd2807SJeff Garzik if (*class == ATA_DEV_UNKNOWN) 1014c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 1015c6fd2807SJeff Garzik 1016c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1017c6fd2807SJeff Garzik return rc; 1018c6fd2807SJeff Garzik } 1019c6fd2807SJeff Garzik 1020ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) 1021ad616ffbSTejun Heo { 1022ad616ffbSTejun Heo int rc; 1023ad616ffbSTejun Heo 1024ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1025ad616ffbSTejun Heo 1026*4447d351STejun Heo ahci_stop_engine(ap); 1027ad616ffbSTejun Heo 1028ad616ffbSTejun Heo rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); 1029ad616ffbSTejun Heo 1030ad616ffbSTejun Heo /* vt8251 needs SError cleared for the port to operate */ 1031ad616ffbSTejun Heo ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); 1032ad616ffbSTejun Heo 1033*4447d351STejun Heo ahci_start_engine(ap); 1034ad616ffbSTejun Heo 1035ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1036ad616ffbSTejun Heo 1037ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1038ad616ffbSTejun Heo * request follow-up softreset. 1039ad616ffbSTejun Heo */ 1040ad616ffbSTejun Heo return rc ?: -EAGAIN; 1041ad616ffbSTejun Heo } 1042ad616ffbSTejun Heo 1043c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class) 1044c6fd2807SJeff Garzik { 1045*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1046c6fd2807SJeff Garzik u32 new_tmp, tmp; 1047c6fd2807SJeff Garzik 1048c6fd2807SJeff Garzik ata_std_postreset(ap, class); 1049c6fd2807SJeff Garzik 1050c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1051c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1052c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1053c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1054c6fd2807SJeff Garzik else 1055c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1056c6fd2807SJeff Garzik if (new_tmp != tmp) { 1057c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1058c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1059c6fd2807SJeff Garzik } 1060c6fd2807SJeff Garzik } 1061c6fd2807SJeff Garzik 1062c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap) 1063c6fd2807SJeff Garzik { 10640d5ff566STejun Heo void __iomem *mmio = ap->ioaddr.cmd_addr; 1065c6fd2807SJeff Garzik 1066c6fd2807SJeff Garzik return readl(mmio + PORT_TFDATA) & 0xFF; 1067c6fd2807SJeff Garzik } 1068c6fd2807SJeff Garzik 1069c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 1070c6fd2807SJeff Garzik { 1071c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1072c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1073c6fd2807SJeff Garzik 1074c6fd2807SJeff Garzik ata_tf_from_fis(d2h_fis, tf); 1075c6fd2807SJeff Garzik } 1076c6fd2807SJeff Garzik 1077c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1078c6fd2807SJeff Garzik { 1079c6fd2807SJeff Garzik struct scatterlist *sg; 1080c6fd2807SJeff Garzik struct ahci_sg *ahci_sg; 1081c6fd2807SJeff Garzik unsigned int n_sg = 0; 1082c6fd2807SJeff Garzik 1083c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1084c6fd2807SJeff Garzik 1085c6fd2807SJeff Garzik /* 1086c6fd2807SJeff Garzik * Next, the S/G list. 1087c6fd2807SJeff Garzik */ 1088c6fd2807SJeff Garzik ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1089c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 1090c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1091c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1092c6fd2807SJeff Garzik 1093c6fd2807SJeff Garzik ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); 1094c6fd2807SJeff Garzik ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); 1095c6fd2807SJeff Garzik ahci_sg->flags_size = cpu_to_le32(sg_len - 1); 1096c6fd2807SJeff Garzik 1097c6fd2807SJeff Garzik ahci_sg++; 1098c6fd2807SJeff Garzik n_sg++; 1099c6fd2807SJeff Garzik } 1100c6fd2807SJeff Garzik 1101c6fd2807SJeff Garzik return n_sg; 1102c6fd2807SJeff Garzik } 1103c6fd2807SJeff Garzik 1104c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1105c6fd2807SJeff Garzik { 1106c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1107c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1108c6fd2807SJeff Garzik int is_atapi = is_atapi_taskfile(&qc->tf); 1109c6fd2807SJeff Garzik void *cmd_tbl; 1110c6fd2807SJeff Garzik u32 opts; 1111c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1112c6fd2807SJeff Garzik unsigned int n_elem; 1113c6fd2807SJeff Garzik 1114c6fd2807SJeff Garzik /* 1115c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1116c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1117c6fd2807SJeff Garzik */ 1118c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1119c6fd2807SJeff Garzik 1120c6fd2807SJeff Garzik ata_tf_to_fis(&qc->tf, cmd_tbl, 0); 1121c6fd2807SJeff Garzik if (is_atapi) { 1122c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1123c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1124c6fd2807SJeff Garzik } 1125c6fd2807SJeff Garzik 1126c6fd2807SJeff Garzik n_elem = 0; 1127c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1128c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1129c6fd2807SJeff Garzik 1130c6fd2807SJeff Garzik /* 1131c6fd2807SJeff Garzik * Fill in command slot information. 1132c6fd2807SJeff Garzik */ 1133c6fd2807SJeff Garzik opts = cmd_fis_len | n_elem << 16; 1134c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1135c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1136c6fd2807SJeff Garzik if (is_atapi) 1137c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1138c6fd2807SJeff Garzik 1139c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1140c6fd2807SJeff Garzik } 1141c6fd2807SJeff Garzik 1142c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1143c6fd2807SJeff Garzik { 1144c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1145c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 1146c6fd2807SJeff Garzik unsigned int err_mask = 0, action = 0; 1147c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 1148c6fd2807SJeff Garzik u32 serror; 1149c6fd2807SJeff Garzik 1150c6fd2807SJeff Garzik ata_ehi_clear_desc(ehi); 1151c6fd2807SJeff Garzik 1152c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1153c6fd2807SJeff Garzik serror = ahci_scr_read(ap, SCR_ERROR); 1154c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 1155c6fd2807SJeff Garzik 1156c6fd2807SJeff Garzik /* analyze @irq_stat */ 1157c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); 1158c6fd2807SJeff Garzik 115941669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 116041669553STejun Heo if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) 116141669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 116241669553STejun Heo 116355a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 1164c6fd2807SJeff Garzik err_mask |= AC_ERR_DEV; 116555a61604SConke Hu if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) 116655a61604SConke Hu serror &= ~SERR_INTERNAL; 116755a61604SConke Hu } 1168c6fd2807SJeff Garzik 1169c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 1170c6fd2807SJeff Garzik err_mask |= AC_ERR_HOST_BUS; 1171c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1172c6fd2807SJeff Garzik } 1173c6fd2807SJeff Garzik 1174c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_IF_ERR) { 1175c6fd2807SJeff Garzik err_mask |= AC_ERR_ATA_BUS; 1176c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1177c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", interface fatal error"); 1178c6fd2807SJeff Garzik } 1179c6fd2807SJeff Garzik 1180c6fd2807SJeff Garzik if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 1181c6fd2807SJeff Garzik ata_ehi_hotplugged(ehi); 1182c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? 1183c6fd2807SJeff Garzik "connection status changed" : "PHY RDY changed"); 1184c6fd2807SJeff Garzik } 1185c6fd2807SJeff Garzik 1186c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1187c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1188c6fd2807SJeff Garzik 1189c6fd2807SJeff Garzik err_mask |= AC_ERR_HSM; 1190c6fd2807SJeff Garzik action |= ATA_EH_SOFTRESET; 1191c6fd2807SJeff Garzik ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", 1192c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1193c6fd2807SJeff Garzik } 1194c6fd2807SJeff Garzik 1195c6fd2807SJeff Garzik /* okay, let's hand over to EH */ 1196c6fd2807SJeff Garzik ehi->serror |= serror; 1197c6fd2807SJeff Garzik ehi->action |= action; 1198c6fd2807SJeff Garzik 1199c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 1200c6fd2807SJeff Garzik if (qc) 1201c6fd2807SJeff Garzik qc->err_mask |= err_mask; 1202c6fd2807SJeff Garzik else 1203c6fd2807SJeff Garzik ehi->err_mask |= err_mask; 1204c6fd2807SJeff Garzik 1205c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1206c6fd2807SJeff Garzik ata_port_freeze(ap); 1207c6fd2807SJeff Garzik else 1208c6fd2807SJeff Garzik ata_port_abort(ap); 1209c6fd2807SJeff Garzik } 1210c6fd2807SJeff Garzik 1211c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap) 1212c6fd2807SJeff Garzik { 1213*4447d351STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 1214c6fd2807SJeff Garzik struct ata_eh_info *ehi = &ap->eh_info; 12150291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 1216c6fd2807SJeff Garzik u32 status, qc_active; 12170291f95fSTejun Heo int rc, known_irq = 0; 1218c6fd2807SJeff Garzik 1219c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1220c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1221c6fd2807SJeff Garzik 1222c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1223c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1224c6fd2807SJeff Garzik return; 1225c6fd2807SJeff Garzik } 1226c6fd2807SJeff Garzik 1227c6fd2807SJeff Garzik if (ap->sactive) 1228c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1229c6fd2807SJeff Garzik else 1230c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1231c6fd2807SJeff Garzik 1232c6fd2807SJeff Garzik rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1233c6fd2807SJeff Garzik if (rc > 0) 1234c6fd2807SJeff Garzik return; 1235c6fd2807SJeff Garzik if (rc < 0) { 1236c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1237c6fd2807SJeff Garzik ehi->action |= ATA_EH_SOFTRESET; 1238c6fd2807SJeff Garzik ata_port_freeze(ap); 1239c6fd2807SJeff Garzik return; 1240c6fd2807SJeff Garzik } 1241c6fd2807SJeff Garzik 1242c6fd2807SJeff Garzik /* hmmm... a spurious interupt */ 1243c6fd2807SJeff Garzik 12440291f95fSTejun Heo /* if !NCQ, ignore. No modern ATA device has broken HSM 12450291f95fSTejun Heo * implementation for non-NCQ commands. 12460291f95fSTejun Heo */ 12470291f95fSTejun Heo if (!ap->sactive) 1248c6fd2807SJeff Garzik return; 1249c6fd2807SJeff Garzik 12500291f95fSTejun Heo if (status & PORT_IRQ_D2H_REG_FIS) { 12510291f95fSTejun Heo if (!pp->ncq_saw_d2h) 12520291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 12530291f95fSTejun Heo "D2H reg with I during NCQ, " 12540291f95fSTejun Heo "this message won't be printed again\n"); 12550291f95fSTejun Heo pp->ncq_saw_d2h = 1; 12560291f95fSTejun Heo known_irq = 1; 12570291f95fSTejun Heo } 1258c6fd2807SJeff Garzik 12590291f95fSTejun Heo if (status & PORT_IRQ_DMAS_FIS) { 12600291f95fSTejun Heo if (!pp->ncq_saw_dmas) 12610291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 12620291f95fSTejun Heo "DMAS FIS during NCQ, " 12630291f95fSTejun Heo "this message won't be printed again\n"); 12640291f95fSTejun Heo pp->ncq_saw_dmas = 1; 12650291f95fSTejun Heo known_irq = 1; 12660291f95fSTejun Heo } 12670291f95fSTejun Heo 1268a2bbd0c9STejun Heo if (status & PORT_IRQ_SDB_FIS) { 126904d4f7a1SAl Viro const __le32 *f = pp->rx_fis + RX_FIS_SDB; 12700291f95fSTejun Heo 1271afb2d552STejun Heo if (le32_to_cpu(f[1])) { 1272afb2d552STejun Heo /* SDB FIS containing spurious completions 1273afb2d552STejun Heo * might be dangerous, whine and fail commands 1274afb2d552STejun Heo * with HSM violation. EH will turn off NCQ 1275afb2d552STejun Heo * after several such failures. 1276afb2d552STejun Heo */ 1277afb2d552STejun Heo ata_ehi_push_desc(ehi, 1278afb2d552STejun Heo "spurious completions during NCQ " 1279a2bbd0c9STejun Heo "issue=0x%x SAct=0x%x FIS=%08x:%08x", 12800291f95fSTejun Heo readl(port_mmio + PORT_CMD_ISSUE), 12816096b63eSTejun Heo readl(port_mmio + PORT_SCR_ACT), 1282a2bbd0c9STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1283a2bbd0c9STejun Heo ehi->err_mask |= AC_ERR_HSM; 1284a2bbd0c9STejun Heo ehi->action |= ATA_EH_SOFTRESET; 1285a2bbd0c9STejun Heo ata_port_freeze(ap); 1286afb2d552STejun Heo } else { 1287afb2d552STejun Heo if (!pp->ncq_saw_sdb) 1288afb2d552STejun Heo ata_port_printk(ap, KERN_INFO, 1289afb2d552STejun Heo "spurious SDB FIS %08x:%08x during NCQ, " 1290afb2d552STejun Heo "this message won't be printed again\n", 1291afb2d552STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1292afb2d552STejun Heo pp->ncq_saw_sdb = 1; 1293afb2d552STejun Heo } 12940291f95fSTejun Heo known_irq = 1; 12950291f95fSTejun Heo } 12960291f95fSTejun Heo 12970291f95fSTejun Heo if (!known_irq) 1298c6fd2807SJeff Garzik ata_port_printk(ap, KERN_INFO, "spurious interrupt " 12990291f95fSTejun Heo "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", 1300c6fd2807SJeff Garzik status, ap->active_tag, ap->sactive); 1301c6fd2807SJeff Garzik } 1302c6fd2807SJeff Garzik 1303c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap) 1304c6fd2807SJeff Garzik { 1305c6fd2807SJeff Garzik /* TODO */ 1306c6fd2807SJeff Garzik } 1307c6fd2807SJeff Garzik 13087d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1309c6fd2807SJeff Garzik { 1310cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1311c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1312c6fd2807SJeff Garzik unsigned int i, handled = 0; 1313c6fd2807SJeff Garzik void __iomem *mmio; 1314c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1315c6fd2807SJeff Garzik 1316c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1317c6fd2807SJeff Garzik 1318cca3974eSJeff Garzik hpriv = host->private_data; 13190d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 1320c6fd2807SJeff Garzik 1321c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1322c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1323c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1324c6fd2807SJeff Garzik if (!irq_stat) 1325c6fd2807SJeff Garzik return IRQ_NONE; 1326c6fd2807SJeff Garzik 1327cca3974eSJeff Garzik spin_lock(&host->lock); 1328c6fd2807SJeff Garzik 1329cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1330c6fd2807SJeff Garzik struct ata_port *ap; 1331c6fd2807SJeff Garzik 1332c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1333c6fd2807SJeff Garzik continue; 1334c6fd2807SJeff Garzik 1335cca3974eSJeff Garzik ap = host->ports[i]; 1336c6fd2807SJeff Garzik if (ap) { 1337c6fd2807SJeff Garzik ahci_host_intr(ap); 1338c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1339c6fd2807SJeff Garzik } else { 1340c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1341c6fd2807SJeff Garzik if (ata_ratelimit()) 1342cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1343c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1344c6fd2807SJeff Garzik } 1345c6fd2807SJeff Garzik 1346c6fd2807SJeff Garzik irq_ack |= (1 << i); 1347c6fd2807SJeff Garzik } 1348c6fd2807SJeff Garzik 1349c6fd2807SJeff Garzik if (irq_ack) { 1350c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1351c6fd2807SJeff Garzik handled = 1; 1352c6fd2807SJeff Garzik } 1353c6fd2807SJeff Garzik 1354cca3974eSJeff Garzik spin_unlock(&host->lock); 1355c6fd2807SJeff Garzik 1356c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1357c6fd2807SJeff Garzik 1358c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1359c6fd2807SJeff Garzik } 1360c6fd2807SJeff Garzik 1361c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1362c6fd2807SJeff Garzik { 1363c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1364*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1365c6fd2807SJeff Garzik 1366c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1367c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1368c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1369c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1370c6fd2807SJeff Garzik 1371c6fd2807SJeff Garzik return 0; 1372c6fd2807SJeff Garzik } 1373c6fd2807SJeff Garzik 1374c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1375c6fd2807SJeff Garzik { 1376*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1377c6fd2807SJeff Garzik 1378c6fd2807SJeff Garzik /* turn IRQ off */ 1379c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1380c6fd2807SJeff Garzik } 1381c6fd2807SJeff Garzik 1382c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1383c6fd2807SJeff Garzik { 13840d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1385*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1386c6fd2807SJeff Garzik u32 tmp; 1387c6fd2807SJeff Garzik 1388c6fd2807SJeff Garzik /* clear IRQ */ 1389c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1390c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1391a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1392c6fd2807SJeff Garzik 1393c6fd2807SJeff Garzik /* turn IRQ back on */ 1394c6fd2807SJeff Garzik writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); 1395c6fd2807SJeff Garzik } 1396c6fd2807SJeff Garzik 1397c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1398c6fd2807SJeff Garzik { 1399c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1400c6fd2807SJeff Garzik /* restart engine */ 1401*4447d351STejun Heo ahci_stop_engine(ap); 1402*4447d351STejun Heo ahci_start_engine(ap); 1403c6fd2807SJeff Garzik } 1404c6fd2807SJeff Garzik 1405c6fd2807SJeff Garzik /* perform recovery */ 14064aeb0e32STejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, 1407c6fd2807SJeff Garzik ahci_postreset); 1408c6fd2807SJeff Garzik } 1409c6fd2807SJeff Garzik 1410ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap) 1411ad616ffbSTejun Heo { 1412ad616ffbSTejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1413ad616ffbSTejun Heo /* restart engine */ 1414*4447d351STejun Heo ahci_stop_engine(ap); 1415*4447d351STejun Heo ahci_start_engine(ap); 1416ad616ffbSTejun Heo } 1417ad616ffbSTejun Heo 1418ad616ffbSTejun Heo /* perform recovery */ 1419ad616ffbSTejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, 1420ad616ffbSTejun Heo ahci_postreset); 1421ad616ffbSTejun Heo } 1422ad616ffbSTejun Heo 1423c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1424c6fd2807SJeff Garzik { 1425c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1426c6fd2807SJeff Garzik 1427a51d644aSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) { 1428c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1429*4447d351STejun Heo ahci_stop_engine(ap); 1430*4447d351STejun Heo ahci_start_engine(ap); 1431c6fd2807SJeff Garzik } 1432c6fd2807SJeff Garzik } 1433c6fd2807SJeff Garzik 1434438ac6d5STejun Heo #ifdef CONFIG_PM 1435c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1436c6fd2807SJeff Garzik { 1437c6fd2807SJeff Garzik const char *emsg = NULL; 1438c6fd2807SJeff Garzik int rc; 1439c6fd2807SJeff Garzik 1440*4447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 14418e16f941STejun Heo if (rc == 0) 1442*4447d351STejun Heo ahci_power_down(ap); 14438e16f941STejun Heo else { 1444c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1445*4447d351STejun Heo ahci_init_port(ap); 1446c6fd2807SJeff Garzik } 1447c6fd2807SJeff Garzik 1448c6fd2807SJeff Garzik return rc; 1449c6fd2807SJeff Garzik } 1450c6fd2807SJeff Garzik 1451c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap) 1452c6fd2807SJeff Garzik { 1453*4447d351STejun Heo ahci_power_up(ap); 1454*4447d351STejun Heo ahci_init_port(ap); 1455c6fd2807SJeff Garzik 1456c6fd2807SJeff Garzik return 0; 1457c6fd2807SJeff Garzik } 1458c6fd2807SJeff Garzik 1459c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1460c6fd2807SJeff Garzik { 1461cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 14620d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1463c6fd2807SJeff Garzik u32 ctl; 1464c6fd2807SJeff Garzik 1465c6fd2807SJeff Garzik if (mesg.event == PM_EVENT_SUSPEND) { 1466c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1467c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1468c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1469c6fd2807SJeff Garzik */ 1470c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1471c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1472c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1473c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1474c6fd2807SJeff Garzik } 1475c6fd2807SJeff Garzik 1476c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1477c6fd2807SJeff Garzik } 1478c6fd2807SJeff Garzik 1479c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1480c6fd2807SJeff Garzik { 1481cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1482c6fd2807SJeff Garzik int rc; 1483c6fd2807SJeff Garzik 1484553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 1485553c4aa6STejun Heo if (rc) 1486553c4aa6STejun Heo return rc; 1487c6fd2807SJeff Garzik 1488c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 1489*4447d351STejun Heo rc = ahci_reset_controller(host); 1490c6fd2807SJeff Garzik if (rc) 1491c6fd2807SJeff Garzik return rc; 1492c6fd2807SJeff Garzik 1493*4447d351STejun Heo ahci_init_controller(host); 1494c6fd2807SJeff Garzik } 1495c6fd2807SJeff Garzik 1496cca3974eSJeff Garzik ata_host_resume(host); 1497c6fd2807SJeff Garzik 1498c6fd2807SJeff Garzik return 0; 1499c6fd2807SJeff Garzik } 1500438ac6d5STejun Heo #endif 1501c6fd2807SJeff Garzik 1502c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1503c6fd2807SJeff Garzik { 1504cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1505c6fd2807SJeff Garzik struct ahci_port_priv *pp; 1506c6fd2807SJeff Garzik void *mem; 1507c6fd2807SJeff Garzik dma_addr_t mem_dma; 1508c6fd2807SJeff Garzik int rc; 1509c6fd2807SJeff Garzik 151024dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 1511c6fd2807SJeff Garzik if (!pp) 1512c6fd2807SJeff Garzik return -ENOMEM; 1513c6fd2807SJeff Garzik 1514c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 151524dc5f33STejun Heo if (rc) 1516c6fd2807SJeff Garzik return rc; 1517c6fd2807SJeff Garzik 151824dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 151924dc5f33STejun Heo GFP_KERNEL); 152024dc5f33STejun Heo if (!mem) 1521c6fd2807SJeff Garzik return -ENOMEM; 1522c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1523c6fd2807SJeff Garzik 1524c6fd2807SJeff Garzik /* 1525c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1526c6fd2807SJeff Garzik * 32 bytes each in size 1527c6fd2807SJeff Garzik */ 1528c6fd2807SJeff Garzik pp->cmd_slot = mem; 1529c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 1530c6fd2807SJeff Garzik 1531c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 1532c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 1533c6fd2807SJeff Garzik 1534c6fd2807SJeff Garzik /* 1535c6fd2807SJeff Garzik * Second item: Received-FIS area 1536c6fd2807SJeff Garzik */ 1537c6fd2807SJeff Garzik pp->rx_fis = mem; 1538c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 1539c6fd2807SJeff Garzik 1540c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 1541c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 1542c6fd2807SJeff Garzik 1543c6fd2807SJeff Garzik /* 1544c6fd2807SJeff Garzik * Third item: data area for storing a single command 1545c6fd2807SJeff Garzik * and its scatter-gather table 1546c6fd2807SJeff Garzik */ 1547c6fd2807SJeff Garzik pp->cmd_tbl = mem; 1548c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 1549c6fd2807SJeff Garzik 1550c6fd2807SJeff Garzik ap->private_data = pp; 1551c6fd2807SJeff Garzik 15528e16f941STejun Heo /* power up port */ 1553*4447d351STejun Heo ahci_power_up(ap); 15548e16f941STejun Heo 1555c6fd2807SJeff Garzik /* initialize port */ 1556*4447d351STejun Heo ahci_init_port(ap); 1557c6fd2807SJeff Garzik 1558c6fd2807SJeff Garzik return 0; 1559c6fd2807SJeff Garzik } 1560c6fd2807SJeff Garzik 1561c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 1562c6fd2807SJeff Garzik { 1563c6fd2807SJeff Garzik const char *emsg = NULL; 1564c6fd2807SJeff Garzik int rc; 1565c6fd2807SJeff Garzik 1566c6fd2807SJeff Garzik /* de-initialize port */ 1567*4447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1568c6fd2807SJeff Garzik if (rc) 1569c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 1570c6fd2807SJeff Garzik } 1571c6fd2807SJeff Garzik 1572*4447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 1573c6fd2807SJeff Garzik { 1574c6fd2807SJeff Garzik int rc; 1575c6fd2807SJeff Garzik 1576c6fd2807SJeff Garzik if (using_dac && 1577c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 1578c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 1579c6fd2807SJeff Garzik if (rc) { 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 "64-bit DMA enable failed\n"); 1584c6fd2807SJeff Garzik return rc; 1585c6fd2807SJeff Garzik } 1586c6fd2807SJeff Garzik } 1587c6fd2807SJeff Garzik } else { 1588c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 1589c6fd2807SJeff Garzik if (rc) { 1590c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1591c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 1592c6fd2807SJeff Garzik return rc; 1593c6fd2807SJeff Garzik } 1594c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1595c6fd2807SJeff Garzik if (rc) { 1596c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1597c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 1598c6fd2807SJeff Garzik return rc; 1599c6fd2807SJeff Garzik } 1600c6fd2807SJeff Garzik } 1601c6fd2807SJeff Garzik return 0; 1602c6fd2807SJeff Garzik } 1603c6fd2807SJeff Garzik 1604*4447d351STejun Heo static void ahci_print_info(struct ata_host *host) 1605c6fd2807SJeff Garzik { 1606*4447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 1607*4447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 1608*4447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1609c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 1610c6fd2807SJeff Garzik const char *speed_s; 1611c6fd2807SJeff Garzik u16 cc; 1612c6fd2807SJeff Garzik const char *scc_s; 1613c6fd2807SJeff Garzik 1614c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 1615c6fd2807SJeff Garzik cap = hpriv->cap; 1616c6fd2807SJeff Garzik impl = hpriv->port_map; 1617c6fd2807SJeff Garzik 1618c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 1619c6fd2807SJeff Garzik if (speed == 1) 1620c6fd2807SJeff Garzik speed_s = "1.5"; 1621c6fd2807SJeff Garzik else if (speed == 2) 1622c6fd2807SJeff Garzik speed_s = "3"; 1623c6fd2807SJeff Garzik else 1624c6fd2807SJeff Garzik speed_s = "?"; 1625c6fd2807SJeff Garzik 1626c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 1627c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 1628c6fd2807SJeff Garzik scc_s = "IDE"; 1629c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 1630c6fd2807SJeff Garzik scc_s = "SATA"; 1631c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 1632c6fd2807SJeff Garzik scc_s = "RAID"; 1633c6fd2807SJeff Garzik else 1634c6fd2807SJeff Garzik scc_s = "unknown"; 1635c6fd2807SJeff Garzik 1636c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1637c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 1638c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 1639c6fd2807SJeff Garzik , 1640c6fd2807SJeff Garzik 1641c6fd2807SJeff Garzik (vers >> 24) & 0xff, 1642c6fd2807SJeff Garzik (vers >> 16) & 0xff, 1643c6fd2807SJeff Garzik (vers >> 8) & 0xff, 1644c6fd2807SJeff Garzik vers & 0xff, 1645c6fd2807SJeff Garzik 1646c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 1647c6fd2807SJeff Garzik (cap & 0x1f) + 1, 1648c6fd2807SJeff Garzik speed_s, 1649c6fd2807SJeff Garzik impl, 1650c6fd2807SJeff Garzik scc_s); 1651c6fd2807SJeff Garzik 1652c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 1653c6fd2807SJeff Garzik "flags: " 1654c6fd2807SJeff Garzik "%s%s%s%s%s%s" 1655c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 1656c6fd2807SJeff Garzik , 1657c6fd2807SJeff Garzik 1658c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 1659c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 1660c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 1661c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 1662c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 1663c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 1664c6fd2807SJeff Garzik 1665c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 1666c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 1667c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 1668c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 1669c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 1670c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 1671c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 1672c6fd2807SJeff Garzik ); 1673c6fd2807SJeff Garzik } 1674c6fd2807SJeff Garzik 1675c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 1676c6fd2807SJeff Garzik { 1677c6fd2807SJeff Garzik static int printed_version; 1678*4447d351STejun Heo struct ata_port_info pi = ahci_port_info[ent->driver_data]; 1679*4447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 168024dc5f33STejun Heo struct device *dev = &pdev->dev; 1681c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1682*4447d351STejun Heo struct ata_host *host; 1683*4447d351STejun Heo int i, rc; 1684c6fd2807SJeff Garzik 1685c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1686c6fd2807SJeff Garzik 1687c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 1688c6fd2807SJeff Garzik 1689c6fd2807SJeff Garzik if (!printed_version++) 1690c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 1691c6fd2807SJeff Garzik 1692*4447d351STejun Heo /* acquire resources */ 169324dc5f33STejun Heo rc = pcim_enable_device(pdev); 1694c6fd2807SJeff Garzik if (rc) 1695c6fd2807SJeff Garzik return rc; 1696c6fd2807SJeff Garzik 16970d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 16980d5ff566STejun Heo if (rc == -EBUSY) 169924dc5f33STejun Heo pcim_pin_device(pdev); 17000d5ff566STejun Heo if (rc) 170124dc5f33STejun Heo return rc; 1702c6fd2807SJeff Garzik 170324dc5f33STejun Heo if (pci_enable_msi(pdev)) 1704c6fd2807SJeff Garzik pci_intx(pdev, 1); 1705c6fd2807SJeff Garzik 170624dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 170724dc5f33STejun Heo if (!hpriv) 170824dc5f33STejun Heo return -ENOMEM; 1709c6fd2807SJeff Garzik 1710*4447d351STejun Heo /* save initial config */ 1711*4447d351STejun Heo ahci_save_initial_config(pdev, &pi, hpriv); 1712c6fd2807SJeff Garzik 1713*4447d351STejun Heo /* prepare host */ 1714*4447d351STejun Heo if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ)) 1715*4447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 1716*4447d351STejun Heo 1717*4447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); 1718*4447d351STejun Heo if (!host) 1719*4447d351STejun Heo return -ENOMEM; 1720*4447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 1721*4447d351STejun Heo host->private_data = hpriv; 1722*4447d351STejun Heo 1723*4447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 1724*4447d351STejun Heo if (hpriv->port_map & (1 << i)) { 1725*4447d351STejun Heo struct ata_port *ap = host->ports[i]; 1726*4447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1727*4447d351STejun Heo 1728*4447d351STejun Heo ap->ioaddr.cmd_addr = port_mmio; 1729*4447d351STejun Heo ap->ioaddr.scr_addr = port_mmio + PORT_SCR; 1730*4447d351STejun Heo } else 1731*4447d351STejun Heo host->ports[i]->ops = &ata_dummy_port_ops; 1732*4447d351STejun Heo } 1733c6fd2807SJeff Garzik 1734c6fd2807SJeff Garzik /* initialize adapter */ 1735*4447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 1736c6fd2807SJeff Garzik if (rc) 173724dc5f33STejun Heo return rc; 1738c6fd2807SJeff Garzik 1739*4447d351STejun Heo rc = ahci_reset_controller(host); 1740*4447d351STejun Heo if (rc) 1741*4447d351STejun Heo return rc; 1742c6fd2807SJeff Garzik 1743*4447d351STejun Heo ahci_init_controller(host); 1744*4447d351STejun Heo ahci_print_info(host); 1745c6fd2807SJeff Garzik 1746*4447d351STejun Heo pci_set_master(pdev); 1747*4447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 1748*4447d351STejun Heo &ahci_sht); 1749c6fd2807SJeff Garzik } 1750c6fd2807SJeff Garzik 1751c6fd2807SJeff Garzik static int __init ahci_init(void) 1752c6fd2807SJeff Garzik { 1753c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 1754c6fd2807SJeff Garzik } 1755c6fd2807SJeff Garzik 1756c6fd2807SJeff Garzik static void __exit ahci_exit(void) 1757c6fd2807SJeff Garzik { 1758c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 1759c6fd2807SJeff Garzik } 1760c6fd2807SJeff Garzik 1761c6fd2807SJeff Garzik 1762c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 1763c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 1764c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 1765c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 1766c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 1767c6fd2807SJeff Garzik 1768c6fd2807SJeff Garzik module_init(ahci_init); 1769c6fd2807SJeff Garzik module_exit(ahci_exit); 1770