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> 44*edc93052STejun Heo #include <linux/dmi.h> 45c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h> 47c6fd2807SJeff Garzik #include <linux/libata.h> 48c6fd2807SJeff Garzik 49c6fd2807SJeff Garzik #define DRV_NAME "ahci" 507d50b60bSTejun Heo #define DRV_VERSION "3.0" 51c6fd2807SJeff Garzik 52c6fd2807SJeff Garzik 53c6fd2807SJeff Garzik enum { 54c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 55648a88beSTejun Heo AHCI_MAX_PORTS = 32, 56c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 57c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 58be5d8218SJens Axboe AHCI_USE_CLUSTERING = 1, 59c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 60c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 61c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 62c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 63c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 64c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 65c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 66c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 67c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 68c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 69c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 70c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 71c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 72c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 73c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 74c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 75c6fd2807SJeff Garzik 76c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 770291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 78c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 79c6fd2807SJeff Garzik 80c6fd2807SJeff Garzik board_ahci = 0, 817a234affSTejun Heo board_ahci_vt8251 = 1, 827a234affSTejun Heo board_ahci_ign_iferr = 2, 837a234affSTejun Heo board_ahci_sb600 = 3, 847a234affSTejun Heo board_ahci_mv = 4, 85c6fd2807SJeff Garzik 86c6fd2807SJeff Garzik /* global controller registers */ 87c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 88c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 89c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 90c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 91c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 92c6fd2807SJeff Garzik 93c6fd2807SJeff Garzik /* HOST_CTL bits */ 94c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 95c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 96c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 97c6fd2807SJeff Garzik 98c6fd2807SJeff Garzik /* HOST_CAP bits */ 99c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 1007d50b60bSTejun Heo HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ 101c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 102c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 103203ef6c4STejun Heo HOST_CAP_SNTF = (1 << 29), /* SNotification register */ 104c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 105c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 106c6fd2807SJeff Garzik 107c6fd2807SJeff Garzik /* registers for each SATA port */ 108c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 109c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 110c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 111c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 112c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 113c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 114c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 115c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 116c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 117c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 118c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 119c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 120c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 121c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 122203ef6c4STejun Heo PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ 123c6fd2807SJeff Garzik 124c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 125c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 126c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 127c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 128c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 129c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 130c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 131c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 132c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 133c6fd2807SJeff Garzik 134c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 135c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 136c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 137c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 138c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 139c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 140c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 141c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 142c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 143c6fd2807SJeff Garzik 144c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 145c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 146c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 147c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 1487d50b60bSTejun Heo PORT_IRQ_UNK_FIS | 1497d50b60bSTejun Heo PORT_IRQ_BAD_PMP, 150c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 151c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 152c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 153c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 154c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 155c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 156c6fd2807SJeff Garzik 157c6fd2807SJeff Garzik /* PORT_CMD bits */ 158c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 1597d50b60bSTejun Heo PORT_CMD_PMP = (1 << 17), /* PMP attached */ 160c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 161c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 162c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 163c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 164c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 165c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 166c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 167c6fd2807SJeff Garzik 168c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 169c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 170c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 171c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 172c6fd2807SJeff Garzik 173417a1a6dSTejun Heo /* hpriv->flags bits */ 174417a1a6dSTejun Heo AHCI_HFLAG_NO_NCQ = (1 << 0), 175417a1a6dSTejun Heo AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ 176417a1a6dSTejun Heo AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ 177417a1a6dSTejun Heo AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ 178417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ 179417a1a6dSTejun Heo AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ 1806949b914STejun Heo AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ 181417a1a6dSTejun Heo 182c6fd2807SJeff Garzik /* ap->flags bits */ 183417a1a6dSTejun Heo AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ 1841188c0d8STejun Heo 1851188c0d8STejun Heo AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 1861188c0d8STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 187854c73a2STejun Heo ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, 1880c88758bSTejun Heo AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, 189c6fd2807SJeff Garzik }; 190c6fd2807SJeff Garzik 191c6fd2807SJeff Garzik struct ahci_cmd_hdr { 192c6fd2807SJeff Garzik u32 opts; 193c6fd2807SJeff Garzik u32 status; 194c6fd2807SJeff Garzik u32 tbl_addr; 195c6fd2807SJeff Garzik u32 tbl_addr_hi; 196c6fd2807SJeff Garzik u32 reserved[4]; 197c6fd2807SJeff Garzik }; 198c6fd2807SJeff Garzik 199c6fd2807SJeff Garzik struct ahci_sg { 200c6fd2807SJeff Garzik u32 addr; 201c6fd2807SJeff Garzik u32 addr_hi; 202c6fd2807SJeff Garzik u32 reserved; 203c6fd2807SJeff Garzik u32 flags_size; 204c6fd2807SJeff Garzik }; 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik struct ahci_host_priv { 207417a1a6dSTejun Heo unsigned int flags; /* AHCI_HFLAG_* */ 208d447df14STejun Heo u32 cap; /* cap to use */ 209d447df14STejun Heo u32 port_map; /* port map to use */ 210d447df14STejun Heo u32 saved_cap; /* saved initial cap */ 211d447df14STejun Heo u32 saved_port_map; /* saved initial port_map */ 212c6fd2807SJeff Garzik }; 213c6fd2807SJeff Garzik 214c6fd2807SJeff Garzik struct ahci_port_priv { 2157d50b60bSTejun Heo struct ata_link *active_link; 216c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 217c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 218c6fd2807SJeff Garzik void *cmd_tbl; 219c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 220c6fd2807SJeff Garzik void *rx_fis; 221c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2220291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2230291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2240291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 225afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 226a7384925SKristen Carlson Accardi u32 intr_mask; /* interrupts to enable */ 227c6fd2807SJeff Garzik }; 228c6fd2807SJeff Garzik 229da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); 230da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); 231c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 232c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 233c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap); 234c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 235c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 236c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 237c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 238c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap); 239c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 240c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 2417d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap); 2427d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap); 243c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 244ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap); 245*edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap); 246c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 247df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 248dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); 249dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 250dab632e8SJeff Garzik u32 opts); 251438ac6d5STejun Heo #ifdef CONFIG_PM 252c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 253c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 254c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 255438ac6d5STejun Heo #endif 256c6fd2807SJeff Garzik 257c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 258c6fd2807SJeff Garzik .module = THIS_MODULE, 259c6fd2807SJeff Garzik .name = DRV_NAME, 260c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 261c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 262c6fd2807SJeff Garzik .change_queue_depth = ata_scsi_change_queue_depth, 263c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 264c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 265c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 266c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 267c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 268c6fd2807SJeff Garzik .use_clustering = AHCI_USE_CLUSTERING, 269c6fd2807SJeff Garzik .proc_name = DRV_NAME, 270c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 271c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 272c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 273c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 274c6fd2807SJeff Garzik }; 275c6fd2807SJeff Garzik 276c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = { 277c6fd2807SJeff Garzik .check_status = ahci_check_status, 278c6fd2807SJeff Garzik .check_altstatus = ahci_check_status, 279c6fd2807SJeff Garzik .dev_select = ata_noop_dev_select, 280c6fd2807SJeff Garzik 281c6fd2807SJeff Garzik .tf_read = ahci_tf_read, 282c6fd2807SJeff Garzik 2837d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 284c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 285c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 286c6fd2807SJeff Garzik 287c6fd2807SJeff Garzik .irq_clear = ahci_irq_clear, 288c6fd2807SJeff Garzik 289c6fd2807SJeff Garzik .scr_read = ahci_scr_read, 290c6fd2807SJeff Garzik .scr_write = ahci_scr_write, 291c6fd2807SJeff Garzik 292c6fd2807SJeff Garzik .freeze = ahci_freeze, 293c6fd2807SJeff Garzik .thaw = ahci_thaw, 294c6fd2807SJeff Garzik 295c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 296c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 297c6fd2807SJeff Garzik 2987d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 2997d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3007d50b60bSTejun Heo 301438ac6d5STejun Heo #ifdef CONFIG_PM 302c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 303c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 304438ac6d5STejun Heo #endif 305c6fd2807SJeff Garzik 306c6fd2807SJeff Garzik .port_start = ahci_port_start, 307c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 308c6fd2807SJeff Garzik }; 309c6fd2807SJeff Garzik 310ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = { 311ad616ffbSTejun Heo .check_status = ahci_check_status, 312ad616ffbSTejun Heo .check_altstatus = ahci_check_status, 313ad616ffbSTejun Heo .dev_select = ata_noop_dev_select, 314ad616ffbSTejun Heo 315ad616ffbSTejun Heo .tf_read = ahci_tf_read, 316ad616ffbSTejun Heo 3177d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 318ad616ffbSTejun Heo .qc_prep = ahci_qc_prep, 319ad616ffbSTejun Heo .qc_issue = ahci_qc_issue, 320ad616ffbSTejun Heo 321ad616ffbSTejun Heo .irq_clear = ahci_irq_clear, 322ad616ffbSTejun Heo 323ad616ffbSTejun Heo .scr_read = ahci_scr_read, 324ad616ffbSTejun Heo .scr_write = ahci_scr_write, 325ad616ffbSTejun Heo 326ad616ffbSTejun Heo .freeze = ahci_freeze, 327ad616ffbSTejun Heo .thaw = ahci_thaw, 328ad616ffbSTejun Heo 329ad616ffbSTejun Heo .error_handler = ahci_vt8251_error_handler, 330ad616ffbSTejun Heo .post_internal_cmd = ahci_post_internal_cmd, 331ad616ffbSTejun Heo 3327d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3337d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3347d50b60bSTejun Heo 335438ac6d5STejun Heo #ifdef CONFIG_PM 336ad616ffbSTejun Heo .port_suspend = ahci_port_suspend, 337ad616ffbSTejun Heo .port_resume = ahci_port_resume, 338438ac6d5STejun Heo #endif 339ad616ffbSTejun Heo 340ad616ffbSTejun Heo .port_start = ahci_port_start, 341ad616ffbSTejun Heo .port_stop = ahci_port_stop, 342ad616ffbSTejun Heo }; 343ad616ffbSTejun Heo 344*edc93052STejun Heo static const struct ata_port_operations ahci_p5wdh_ops = { 345*edc93052STejun Heo .check_status = ahci_check_status, 346*edc93052STejun Heo .check_altstatus = ahci_check_status, 347*edc93052STejun Heo .dev_select = ata_noop_dev_select, 348*edc93052STejun Heo 349*edc93052STejun Heo .tf_read = ahci_tf_read, 350*edc93052STejun Heo 351*edc93052STejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 352*edc93052STejun Heo .qc_prep = ahci_qc_prep, 353*edc93052STejun Heo .qc_issue = ahci_qc_issue, 354*edc93052STejun Heo 355*edc93052STejun Heo .irq_clear = ahci_irq_clear, 356*edc93052STejun Heo 357*edc93052STejun Heo .scr_read = ahci_scr_read, 358*edc93052STejun Heo .scr_write = ahci_scr_write, 359*edc93052STejun Heo 360*edc93052STejun Heo .freeze = ahci_freeze, 361*edc93052STejun Heo .thaw = ahci_thaw, 362*edc93052STejun Heo 363*edc93052STejun Heo .error_handler = ahci_p5wdh_error_handler, 364*edc93052STejun Heo .post_internal_cmd = ahci_post_internal_cmd, 365*edc93052STejun Heo 366*edc93052STejun Heo .pmp_attach = ahci_pmp_attach, 367*edc93052STejun Heo .pmp_detach = ahci_pmp_detach, 368*edc93052STejun Heo 369*edc93052STejun Heo #ifdef CONFIG_PM 370*edc93052STejun Heo .port_suspend = ahci_port_suspend, 371*edc93052STejun Heo .port_resume = ahci_port_resume, 372*edc93052STejun Heo #endif 373*edc93052STejun Heo 374*edc93052STejun Heo .port_start = ahci_port_start, 375*edc93052STejun Heo .port_stop = ahci_port_stop, 376*edc93052STejun Heo }; 377*edc93052STejun Heo 378417a1a6dSTejun Heo #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 379417a1a6dSTejun Heo 380c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 381c6fd2807SJeff Garzik /* board_ahci */ 382c6fd2807SJeff Garzik { 3831188c0d8STejun Heo .flags = AHCI_FLAG_COMMON, 3840c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 385c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 386469248abSJeff Garzik .udma_mask = ATA_UDMA6, 387c6fd2807SJeff Garzik .port_ops = &ahci_ops, 388c6fd2807SJeff Garzik }, 389c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 390c6fd2807SJeff Garzik { 3916949b914STejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), 392417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 3930c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, 394c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 395469248abSJeff Garzik .udma_mask = ATA_UDMA6, 396ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 397c6fd2807SJeff Garzik }, 39841669553STejun Heo /* board_ahci_ign_iferr */ 39941669553STejun Heo { 400417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), 401417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 4020c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 40341669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 404469248abSJeff Garzik .udma_mask = ATA_UDMA6, 40541669553STejun Heo .port_ops = &ahci_ops, 40641669553STejun Heo }, 40755a61604SConke Hu /* board_ahci_sb600 */ 40855a61604SConke Hu { 409417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 4106949b914STejun Heo AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), 411417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 4120c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 41355a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 414469248abSJeff Garzik .udma_mask = ATA_UDMA6, 41555a61604SConke Hu .port_ops = &ahci_ops, 41655a61604SConke Hu }, 417cd70c266SJeff Garzik /* board_ahci_mv */ 418cd70c266SJeff Garzik { 419417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | 420417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA), 421cd70c266SJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 422417a1a6dSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 4230c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 424cd70c266SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 425cd70c266SJeff Garzik .udma_mask = ATA_UDMA6, 426cd70c266SJeff Garzik .port_ops = &ahci_ops, 427cd70c266SJeff Garzik }, 428c6fd2807SJeff Garzik }; 429c6fd2807SJeff Garzik 430c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 431c6fd2807SJeff Garzik /* Intel */ 43254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 43354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 43454bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 43554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 43654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 43782490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 43854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 43954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 44054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 44154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 4427a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ 4437a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ 4447a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ 4457a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ 4467a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ 4477a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ 4487a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ 4497a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ 4507a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ 4517a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ 4527a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ 4537a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ 4547a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ 4557a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ 4567a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ 4577a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ 4587a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ 459d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ 460d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ 461c6fd2807SJeff Garzik 462e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 463e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 464e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 465c6fd2807SJeff Garzik 466c6fd2807SJeff Garzik /* ATI */ 467c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 468c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */ 469c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */ 470c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */ 471c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */ 472c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */ 473c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */ 474c6fd2807SJeff Garzik 475c6fd2807SJeff Garzik /* VIA */ 47654bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 477bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 478c6fd2807SJeff Garzik 479c6fd2807SJeff Garzik /* NVIDIA */ 48054bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ 48154bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ 48254bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ 48354bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ 4846fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ 4856fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ 4866fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ 4876fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ 4886fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 4896fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 4906fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 4916fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 492895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 493895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 494895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 495895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 496895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 497895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 498895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 499895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 5000522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */ 5010522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */ 5020522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */ 5030522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */ 5040522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */ 5050522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */ 5060522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */ 5070522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */ 5080522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */ 5090522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */ 5100522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */ 5110522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */ 5120522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */ 5130522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */ 5140522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */ 5150522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */ 5160522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */ 5170522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */ 5180522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */ 5190522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */ 5200522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */ 5210522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ 5220522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ 5230522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ 5247100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ 5257100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ 5267100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ 5277100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ 5287100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ 5297100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ 5307100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ 5317100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ 532c6fd2807SJeff Garzik 533c6fd2807SJeff Garzik /* SiS */ 53454bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 53554bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 53654bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 537c6fd2807SJeff Garzik 538cd70c266SJeff Garzik /* Marvell */ 539cd70c266SJeff Garzik { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ 540cd70c266SJeff Garzik 541415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 542415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 543c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 544415ae2b5SJeff Garzik 545c6fd2807SJeff Garzik { } /* terminate list */ 546c6fd2807SJeff Garzik }; 547c6fd2807SJeff Garzik 548c6fd2807SJeff Garzik 549c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 550c6fd2807SJeff Garzik .name = DRV_NAME, 551c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 552c6fd2807SJeff Garzik .probe = ahci_init_one, 55324dc5f33STejun Heo .remove = ata_pci_remove_one, 554438ac6d5STejun Heo #ifdef CONFIG_PM 555c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 556c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 557438ac6d5STejun Heo #endif 558c6fd2807SJeff Garzik }; 559c6fd2807SJeff Garzik 560c6fd2807SJeff Garzik 56198fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 56298fa4b60STejun Heo { 56398fa4b60STejun Heo return (cap & 0x1f) + 1; 56498fa4b60STejun Heo } 56598fa4b60STejun Heo 566dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host, 567dab632e8SJeff Garzik unsigned int port_no) 568dab632e8SJeff Garzik { 569dab632e8SJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 570dab632e8SJeff Garzik 571dab632e8SJeff Garzik return mmio + 0x100 + (port_no * 0x80); 572dab632e8SJeff Garzik } 573dab632e8SJeff Garzik 5744447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 575c6fd2807SJeff Garzik { 576dab632e8SJeff Garzik return __ahci_port_base(ap->host, ap->port_no); 577c6fd2807SJeff Garzik } 578c6fd2807SJeff Garzik 579d447df14STejun Heo /** 580d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 5814447d351STejun Heo * @pdev: target PCI device 5824447d351STejun Heo * @hpriv: host private area to store config values 583d447df14STejun Heo * 584d447df14STejun Heo * Some registers containing configuration info might be setup by 585d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 586d447df14STejun Heo * initial values of those registers into @hpriv such that they 587d447df14STejun Heo * can be restored after controller reset. 588d447df14STejun Heo * 589d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 590d447df14STejun Heo * 591d447df14STejun Heo * LOCKING: 592d447df14STejun Heo * None. 593d447df14STejun Heo */ 5944447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 5954447d351STejun Heo struct ahci_host_priv *hpriv) 596d447df14STejun Heo { 5974447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 598d447df14STejun Heo u32 cap, port_map; 59917199b18STejun Heo int i; 600d447df14STejun Heo 601d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 602d447df14STejun Heo * reset. Values without are used for driver operation. 603d447df14STejun Heo */ 604d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 605d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 606d447df14STejun Heo 607274c1fdeSTejun Heo /* some chips have errata preventing 64bit use */ 608417a1a6dSTejun Heo if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { 609c7a42156STejun Heo dev_printk(KERN_INFO, &pdev->dev, 610c7a42156STejun Heo "controller can't do 64bit DMA, forcing 32bit\n"); 611c7a42156STejun Heo cap &= ~HOST_CAP_64; 612c7a42156STejun Heo } 613c7a42156STejun Heo 614417a1a6dSTejun Heo if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { 615274c1fdeSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 616274c1fdeSTejun Heo "controller can't do NCQ, turning off CAP_NCQ\n"); 617274c1fdeSTejun Heo cap &= ~HOST_CAP_NCQ; 618274c1fdeSTejun Heo } 619274c1fdeSTejun Heo 6206949b914STejun Heo if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { 6216949b914STejun Heo dev_printk(KERN_INFO, &pdev->dev, 6226949b914STejun Heo "controller can't do PMP, turning off CAP_PMP\n"); 6236949b914STejun Heo cap &= ~HOST_CAP_PMP; 6246949b914STejun Heo } 6256949b914STejun Heo 626cd70c266SJeff Garzik /* 627cd70c266SJeff Garzik * Temporary Marvell 6145 hack: PATA port presence 628cd70c266SJeff Garzik * is asserted through the standard AHCI port 629cd70c266SJeff Garzik * presence register, as bit 4 (counting from 0) 630cd70c266SJeff Garzik */ 631417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 632cd70c266SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 633cd70c266SJeff Garzik "MV_AHCI HACK: port_map %x -> %x\n", 634cd70c266SJeff Garzik hpriv->port_map, 635cd70c266SJeff Garzik hpriv->port_map & 0xf); 636cd70c266SJeff Garzik 637cd70c266SJeff Garzik port_map &= 0xf; 638cd70c266SJeff Garzik } 639cd70c266SJeff Garzik 64017199b18STejun Heo /* cross check port_map and cap.n_ports */ 6417a234affSTejun Heo if (port_map) { 64217199b18STejun Heo u32 tmp_port_map = port_map; 64317199b18STejun Heo int n_ports = ahci_nr_ports(cap); 64417199b18STejun Heo 64517199b18STejun Heo for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { 64617199b18STejun Heo if (tmp_port_map & (1 << i)) { 64717199b18STejun Heo n_ports--; 64817199b18STejun Heo tmp_port_map &= ~(1 << i); 64917199b18STejun Heo } 65017199b18STejun Heo } 65117199b18STejun Heo 6527a234affSTejun Heo /* If n_ports and port_map are inconsistent, whine and 6537a234affSTejun Heo * clear port_map and let it be generated from n_ports. 65417199b18STejun Heo */ 6557a234affSTejun Heo if (n_ports || tmp_port_map) { 6564447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 65717199b18STejun Heo "nr_ports (%u) and implemented port map " 6587a234affSTejun Heo "(0x%x) don't match, using nr_ports\n", 65917199b18STejun Heo ahci_nr_ports(cap), port_map); 6607a234affSTejun Heo port_map = 0; 6617a234affSTejun Heo } 6627a234affSTejun Heo } 6637a234affSTejun Heo 66417199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 6657a234affSTejun Heo if (!port_map) { 66617199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 6677a234affSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 6687a234affSTejun Heo "forcing PORTS_IMPL to 0x%x\n", port_map); 6697a234affSTejun Heo 6707a234affSTejun Heo /* write the fixed up value to the PI register */ 6717a234affSTejun Heo hpriv->saved_port_map = port_map; 67217199b18STejun Heo } 67317199b18STejun Heo 674d447df14STejun Heo /* record values to use during operation */ 675d447df14STejun Heo hpriv->cap = cap; 676d447df14STejun Heo hpriv->port_map = port_map; 677d447df14STejun Heo } 678d447df14STejun Heo 679d447df14STejun Heo /** 680d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 6814447d351STejun Heo * @host: target ATA host 682d447df14STejun Heo * 683d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 684d447df14STejun Heo * 685d447df14STejun Heo * LOCKING: 686d447df14STejun Heo * None. 687d447df14STejun Heo */ 6884447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 689d447df14STejun Heo { 6904447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 6914447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 6924447d351STejun Heo 693d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 694d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 695d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 696d447df14STejun Heo } 697d447df14STejun Heo 698203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) 699c6fd2807SJeff Garzik { 700203ef6c4STejun Heo static const int offset[] = { 701203ef6c4STejun Heo [SCR_STATUS] = PORT_SCR_STAT, 702203ef6c4STejun Heo [SCR_CONTROL] = PORT_SCR_CTL, 703203ef6c4STejun Heo [SCR_ERROR] = PORT_SCR_ERR, 704203ef6c4STejun Heo [SCR_ACTIVE] = PORT_SCR_ACT, 705203ef6c4STejun Heo [SCR_NOTIFICATION] = PORT_SCR_NTF, 706203ef6c4STejun Heo }; 707203ef6c4STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 708c6fd2807SJeff Garzik 709203ef6c4STejun Heo if (sc_reg < ARRAY_SIZE(offset) && 710203ef6c4STejun Heo (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) 711203ef6c4STejun Heo return offset[sc_reg]; 712da3dbb17STejun Heo return 0; 713c6fd2807SJeff Garzik } 714c6fd2807SJeff Garzik 715203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 716c6fd2807SJeff Garzik { 717203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 718203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 719c6fd2807SJeff Garzik 720203ef6c4STejun Heo if (offset) { 721203ef6c4STejun Heo *val = readl(port_mmio + offset); 722203ef6c4STejun Heo return 0; 723203ef6c4STejun Heo } 724da3dbb17STejun Heo return -EINVAL; 725c6fd2807SJeff Garzik } 726c6fd2807SJeff Garzik 727203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 728203ef6c4STejun Heo { 729203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 730203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 731203ef6c4STejun Heo 732203ef6c4STejun Heo if (offset) { 733203ef6c4STejun Heo writel(val, port_mmio + offset); 734da3dbb17STejun Heo return 0; 735c6fd2807SJeff Garzik } 736203ef6c4STejun Heo return -EINVAL; 737203ef6c4STejun Heo } 738c6fd2807SJeff Garzik 7394447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 740c6fd2807SJeff Garzik { 7414447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 742c6fd2807SJeff Garzik u32 tmp; 743c6fd2807SJeff Garzik 744c6fd2807SJeff Garzik /* start DMA */ 745c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 746c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 747c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 748c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 749c6fd2807SJeff Garzik } 750c6fd2807SJeff Garzik 7514447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 752c6fd2807SJeff Garzik { 7534447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 754c6fd2807SJeff Garzik u32 tmp; 755c6fd2807SJeff Garzik 756c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 757c6fd2807SJeff Garzik 758c6fd2807SJeff Garzik /* check if the HBA is idle */ 759c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 760c6fd2807SJeff Garzik return 0; 761c6fd2807SJeff Garzik 762c6fd2807SJeff Garzik /* setting HBA to idle */ 763c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 764c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 765c6fd2807SJeff Garzik 766c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 767c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 768c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 769c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 770c6fd2807SJeff Garzik return -EIO; 771c6fd2807SJeff Garzik 772c6fd2807SJeff Garzik return 0; 773c6fd2807SJeff Garzik } 774c6fd2807SJeff Garzik 7754447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 776c6fd2807SJeff Garzik { 7774447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 7784447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 7794447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 780c6fd2807SJeff Garzik u32 tmp; 781c6fd2807SJeff Garzik 782c6fd2807SJeff Garzik /* set FIS registers */ 7834447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 7844447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 7854447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 7864447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 787c6fd2807SJeff Garzik 7884447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 7894447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 7904447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 7914447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 792c6fd2807SJeff Garzik 793c6fd2807SJeff Garzik /* enable FIS reception */ 794c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 795c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 796c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 797c6fd2807SJeff Garzik 798c6fd2807SJeff Garzik /* flush */ 799c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 800c6fd2807SJeff Garzik } 801c6fd2807SJeff Garzik 8024447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 803c6fd2807SJeff Garzik { 8044447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 805c6fd2807SJeff Garzik u32 tmp; 806c6fd2807SJeff Garzik 807c6fd2807SJeff Garzik /* disable FIS reception */ 808c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 809c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 810c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 811c6fd2807SJeff Garzik 812c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 813c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 814c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 815c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 816c6fd2807SJeff Garzik return -EBUSY; 817c6fd2807SJeff Garzik 818c6fd2807SJeff Garzik return 0; 819c6fd2807SJeff Garzik } 820c6fd2807SJeff Garzik 8214447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 822c6fd2807SJeff Garzik { 8234447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8244447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 825c6fd2807SJeff Garzik u32 cmd; 826c6fd2807SJeff Garzik 827c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 828c6fd2807SJeff Garzik 829c6fd2807SJeff Garzik /* spin up device */ 8304447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 831c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 832c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 833c6fd2807SJeff Garzik } 834c6fd2807SJeff Garzik 835c6fd2807SJeff Garzik /* wake up link */ 836c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 837c6fd2807SJeff Garzik } 838c6fd2807SJeff Garzik 839438ac6d5STejun Heo #ifdef CONFIG_PM 8404447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 841c6fd2807SJeff Garzik { 8424447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8434447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 844c6fd2807SJeff Garzik u32 cmd, scontrol; 845c6fd2807SJeff Garzik 8464447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 84707c53dacSTejun Heo return; 848c6fd2807SJeff Garzik 84907c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 850c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 851c6fd2807SJeff Garzik scontrol &= ~0xf; 852c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 853c6fd2807SJeff Garzik 854c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 85507c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 856c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 857c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 858c6fd2807SJeff Garzik } 859438ac6d5STejun Heo #endif 860c6fd2807SJeff Garzik 861df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap) 862c6fd2807SJeff Garzik { 863c6fd2807SJeff Garzik /* enable FIS reception */ 8644447d351STejun Heo ahci_start_fis_rx(ap); 865c6fd2807SJeff Garzik 866c6fd2807SJeff Garzik /* enable DMA */ 8674447d351STejun Heo ahci_start_engine(ap); 868c6fd2807SJeff Garzik } 869c6fd2807SJeff Garzik 8704447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 871c6fd2807SJeff Garzik { 872c6fd2807SJeff Garzik int rc; 873c6fd2807SJeff Garzik 874c6fd2807SJeff Garzik /* disable DMA */ 8754447d351STejun Heo rc = ahci_stop_engine(ap); 876c6fd2807SJeff Garzik if (rc) { 877c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 878c6fd2807SJeff Garzik return rc; 879c6fd2807SJeff Garzik } 880c6fd2807SJeff Garzik 881c6fd2807SJeff Garzik /* disable FIS reception */ 8824447d351STejun Heo rc = ahci_stop_fis_rx(ap); 883c6fd2807SJeff Garzik if (rc) { 884c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 885c6fd2807SJeff Garzik return rc; 886c6fd2807SJeff Garzik } 887c6fd2807SJeff Garzik 888c6fd2807SJeff Garzik return 0; 889c6fd2807SJeff Garzik } 890c6fd2807SJeff Garzik 8914447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 892c6fd2807SJeff Garzik { 8934447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 8944447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 895d447df14STejun Heo u32 tmp; 896c6fd2807SJeff Garzik 8973cc3eb11SJeff Garzik /* we must be in AHCI mode, before using anything 8983cc3eb11SJeff Garzik * AHCI-specific, such as HOST_RESET. 8993cc3eb11SJeff Garzik */ 900c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 9013cc3eb11SJeff Garzik if (!(tmp & HOST_AHCI_EN)) 9023cc3eb11SJeff Garzik writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL); 9033cc3eb11SJeff Garzik 9043cc3eb11SJeff Garzik /* global controller reset */ 905c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 906c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 907c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 908c6fd2807SJeff Garzik } 909c6fd2807SJeff Garzik 910c6fd2807SJeff Garzik /* reset must complete within 1 second, or 911c6fd2807SJeff Garzik * the hardware should be considered fried. 912c6fd2807SJeff Garzik */ 913c6fd2807SJeff Garzik ssleep(1); 914c6fd2807SJeff Garzik 915c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 916c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 9174447d351STejun Heo dev_printk(KERN_ERR, host->dev, 918c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 919c6fd2807SJeff Garzik return -EIO; 920c6fd2807SJeff Garzik } 921c6fd2807SJeff Garzik 92298fa4b60STejun Heo /* turn on AHCI mode */ 923c6fd2807SJeff Garzik writel(HOST_AHCI_EN, mmio + HOST_CTL); 924c6fd2807SJeff Garzik (void) readl(mmio + HOST_CTL); /* flush */ 92598fa4b60STejun Heo 926d447df14STejun Heo /* some registers might be cleared on reset. restore initial values */ 9274447d351STejun Heo ahci_restore_initial_config(host); 928c6fd2807SJeff Garzik 929c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 930c6fd2807SJeff Garzik u16 tmp16; 931c6fd2807SJeff Garzik 932c6fd2807SJeff Garzik /* configure PCS */ 933c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 934c6fd2807SJeff Garzik tmp16 |= 0xf; 935c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 936c6fd2807SJeff Garzik } 937c6fd2807SJeff Garzik 938c6fd2807SJeff Garzik return 0; 939c6fd2807SJeff Garzik } 940c6fd2807SJeff Garzik 9412bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, 9422bcd866bSJeff Garzik int port_no, void __iomem *mmio, 9432bcd866bSJeff Garzik void __iomem *port_mmio) 944c6fd2807SJeff Garzik { 945c6fd2807SJeff Garzik const char *emsg = NULL; 9462bcd866bSJeff Garzik int rc; 9472bcd866bSJeff Garzik u32 tmp; 948c6fd2807SJeff Garzik 949c6fd2807SJeff Garzik /* make sure port is not active */ 9504447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 951c6fd2807SJeff Garzik if (rc) 952c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 953c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 954c6fd2807SJeff Garzik 955c6fd2807SJeff Garzik /* clear SError */ 956c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 957c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 958c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 959c6fd2807SJeff Garzik 960c6fd2807SJeff Garzik /* clear port IRQ */ 961c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 962c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 963c6fd2807SJeff Garzik if (tmp) 964c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 965c6fd2807SJeff Garzik 9662bcd866bSJeff Garzik writel(1 << port_no, mmio + HOST_IRQ_STAT); 9672bcd866bSJeff Garzik } 9682bcd866bSJeff Garzik 9692bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host) 9702bcd866bSJeff Garzik { 971417a1a6dSTejun Heo struct ahci_host_priv *hpriv = host->private_data; 9722bcd866bSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 9732bcd866bSJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 9742bcd866bSJeff Garzik int i; 975cd70c266SJeff Garzik void __iomem *port_mmio; 9762bcd866bSJeff Garzik u32 tmp; 9772bcd866bSJeff Garzik 978417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 979cd70c266SJeff Garzik port_mmio = __ahci_port_base(host, 4); 980cd70c266SJeff Garzik 981cd70c266SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 982cd70c266SJeff Garzik 983cd70c266SJeff Garzik /* clear port IRQ */ 984cd70c266SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 985cd70c266SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 986cd70c266SJeff Garzik if (tmp) 987cd70c266SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 988cd70c266SJeff Garzik } 989cd70c266SJeff Garzik 9902bcd866bSJeff Garzik for (i = 0; i < host->n_ports; i++) { 9912bcd866bSJeff Garzik struct ata_port *ap = host->ports[i]; 9922bcd866bSJeff Garzik 993cd70c266SJeff Garzik port_mmio = ahci_port_base(ap); 9942bcd866bSJeff Garzik if (ata_port_is_dummy(ap)) 9952bcd866bSJeff Garzik continue; 9962bcd866bSJeff Garzik 9972bcd866bSJeff Garzik ahci_port_init(pdev, ap, i, mmio, port_mmio); 998c6fd2807SJeff Garzik } 999c6fd2807SJeff Garzik 1000c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1001c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1002c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 1003c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1004c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1005c6fd2807SJeff Garzik } 1006c6fd2807SJeff Garzik 1007c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 1008c6fd2807SJeff Garzik { 10094447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1010c6fd2807SJeff Garzik struct ata_taskfile tf; 1011c6fd2807SJeff Garzik u32 tmp; 1012c6fd2807SJeff Garzik 1013c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 1014c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 1015c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 1016c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 1017c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 1018c6fd2807SJeff Garzik 1019c6fd2807SJeff Garzik return ata_dev_classify(&tf); 1020c6fd2807SJeff Garzik } 1021c6fd2807SJeff Garzik 1022c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 1023c6fd2807SJeff Garzik u32 opts) 1024c6fd2807SJeff Garzik { 1025c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 1026c6fd2807SJeff Garzik 1027c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 1028c6fd2807SJeff Garzik 1029c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 1030c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 1031c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 1032c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 1033c6fd2807SJeff Garzik } 1034c6fd2807SJeff Garzik 1035d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart) 1036c6fd2807SJeff Garzik { 10370d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 1038cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1039c6fd2807SJeff Garzik u32 tmp; 1040d2e75dffSTejun Heo int busy, rc; 1041c6fd2807SJeff Garzik 1042d2e75dffSTejun Heo /* do we need to kick the port? */ 1043d2e75dffSTejun Heo busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ); 1044d2e75dffSTejun Heo if (!busy && !force_restart) 1045d2e75dffSTejun Heo return 0; 1046c6fd2807SJeff Garzik 1047d2e75dffSTejun Heo /* stop engine */ 1048d2e75dffSTejun Heo rc = ahci_stop_engine(ap); 1049d2e75dffSTejun Heo if (rc) 1050d2e75dffSTejun Heo goto out_restart; 1051d2e75dffSTejun Heo 1052d2e75dffSTejun Heo /* need to do CLO? */ 1053d2e75dffSTejun Heo if (!busy) { 1054d2e75dffSTejun Heo rc = 0; 1055d2e75dffSTejun Heo goto out_restart; 1056d2e75dffSTejun Heo } 1057d2e75dffSTejun Heo 1058d2e75dffSTejun Heo if (!(hpriv->cap & HOST_CAP_CLO)) { 1059d2e75dffSTejun Heo rc = -EOPNOTSUPP; 1060d2e75dffSTejun Heo goto out_restart; 1061d2e75dffSTejun Heo } 1062d2e75dffSTejun Heo 1063d2e75dffSTejun Heo /* perform CLO */ 1064c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 1065c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 1066c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 1067c6fd2807SJeff Garzik 1068d2e75dffSTejun Heo rc = 0; 1069c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 1070c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 1071c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 1072d2e75dffSTejun Heo rc = -EIO; 1073c6fd2807SJeff Garzik 1074d2e75dffSTejun Heo /* restart engine */ 1075d2e75dffSTejun Heo out_restart: 1076d2e75dffSTejun Heo ahci_start_engine(ap); 1077d2e75dffSTejun Heo return rc; 1078c6fd2807SJeff Garzik } 1079c6fd2807SJeff Garzik 108091c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, 108191c4a2e0STejun Heo struct ata_taskfile *tf, int is_cmd, u16 flags, 108291c4a2e0STejun Heo unsigned long timeout_msec) 108391c4a2e0STejun Heo { 108491c4a2e0STejun Heo const u32 cmd_fis_len = 5; /* five dwords */ 108591c4a2e0STejun Heo struct ahci_port_priv *pp = ap->private_data; 108691c4a2e0STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 108791c4a2e0STejun Heo u8 *fis = pp->cmd_tbl; 108891c4a2e0STejun Heo u32 tmp; 108991c4a2e0STejun Heo 109091c4a2e0STejun Heo /* prep the command */ 109191c4a2e0STejun Heo ata_tf_to_fis(tf, pmp, is_cmd, fis); 109291c4a2e0STejun Heo ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); 109391c4a2e0STejun Heo 109491c4a2e0STejun Heo /* issue & wait */ 109591c4a2e0STejun Heo writel(1, port_mmio + PORT_CMD_ISSUE); 109691c4a2e0STejun Heo 109791c4a2e0STejun Heo if (timeout_msec) { 109891c4a2e0STejun Heo tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 109991c4a2e0STejun Heo 1, timeout_msec); 110091c4a2e0STejun Heo if (tmp & 0x1) { 110191c4a2e0STejun Heo ahci_kick_engine(ap, 1); 110291c4a2e0STejun Heo return -EBUSY; 110391c4a2e0STejun Heo } 110491c4a2e0STejun Heo } else 110591c4a2e0STejun Heo readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 110691c4a2e0STejun Heo 110791c4a2e0STejun Heo return 0; 110891c4a2e0STejun Heo } 110991c4a2e0STejun Heo 1110cc0680a5STejun Heo static int ahci_do_softreset(struct ata_link *link, unsigned int *class, 1111a9cf5e85STejun Heo int pmp, unsigned long deadline) 1112c6fd2807SJeff Garzik { 1113cc0680a5STejun Heo struct ata_port *ap = link->ap; 1114c6fd2807SJeff Garzik const char *reason = NULL; 11152cbb79ebSTejun Heo unsigned long now, msecs; 1116c6fd2807SJeff Garzik struct ata_taskfile tf; 1117c6fd2807SJeff Garzik int rc; 1118c6fd2807SJeff Garzik 1119c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1120c6fd2807SJeff Garzik 1121cc0680a5STejun Heo if (ata_link_offline(link)) { 1122c6fd2807SJeff Garzik DPRINTK("PHY reports no device\n"); 1123c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 1124c6fd2807SJeff Garzik return 0; 1125c6fd2807SJeff Garzik } 1126c6fd2807SJeff Garzik 1127c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 1128d2e75dffSTejun Heo rc = ahci_kick_engine(ap, 1); 1129d2e75dffSTejun Heo if (rc) 1130cc0680a5STejun Heo ata_link_printk(link, KERN_WARNING, 1131d2e75dffSTejun Heo "failed to reset engine (errno=%d)", rc); 1132c6fd2807SJeff Garzik 1133cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1134c6fd2807SJeff Garzik 1135c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 11362cbb79ebSTejun Heo msecs = 0; 11372cbb79ebSTejun Heo now = jiffies; 11382cbb79ebSTejun Heo if (time_after(now, deadline)) 11392cbb79ebSTejun Heo msecs = jiffies_to_msecs(deadline - now); 11402cbb79ebSTejun Heo 1141c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 1142a9cf5e85STejun Heo if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, 114391c4a2e0STejun Heo AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { 1144c6fd2807SJeff Garzik rc = -EIO; 1145c6fd2807SJeff Garzik reason = "1st FIS failed"; 1146c6fd2807SJeff Garzik goto fail; 1147c6fd2807SJeff Garzik } 1148c6fd2807SJeff Garzik 1149c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 1150c6fd2807SJeff Garzik msleep(1); 1151c6fd2807SJeff Garzik 1152c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 1153c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 1154a9cf5e85STejun Heo ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1155c6fd2807SJeff Garzik 1156c6fd2807SJeff Garzik /* spec mandates ">= 2ms" before checking status. 1157c6fd2807SJeff Garzik * We wait 150ms, because that was the magic delay used for 1158c6fd2807SJeff Garzik * ATAPI devices in Hale Landis's ATADRVR, for the period of time 1159c6fd2807SJeff Garzik * between when the ATA command register is written, and then 1160c6fd2807SJeff Garzik * status is checked. Because waiting for "a while" before 1161c6fd2807SJeff Garzik * checking status is fine, post SRST, we perform this magic 1162c6fd2807SJeff Garzik * delay here as well. 1163c6fd2807SJeff Garzik */ 1164c6fd2807SJeff Garzik msleep(150); 1165c6fd2807SJeff Garzik 1166d4b2bab4STejun Heo rc = ata_wait_ready(ap, deadline); 11679b89391cSTejun Heo /* link occupied, -ENODEV too is an error */ 11689b89391cSTejun Heo if (rc) { 1169c6fd2807SJeff Garzik reason = "device not ready"; 1170c6fd2807SJeff Garzik goto fail; 1171c6fd2807SJeff Garzik } 1172c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1173c6fd2807SJeff Garzik 1174c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 1175c6fd2807SJeff Garzik return 0; 1176c6fd2807SJeff Garzik 1177c6fd2807SJeff Garzik fail: 1178cc0680a5STejun Heo ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); 1179c6fd2807SJeff Garzik return rc; 1180c6fd2807SJeff Garzik } 1181c6fd2807SJeff Garzik 1182cc0680a5STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class, 1183a9cf5e85STejun Heo unsigned long deadline) 1184a9cf5e85STejun Heo { 11857d50b60bSTejun Heo int pmp = 0; 11867d50b60bSTejun Heo 11877d50b60bSTejun Heo if (link->ap->flags & ATA_FLAG_PMP) 11887d50b60bSTejun Heo pmp = SATA_PMP_CTRL_PORT; 11897d50b60bSTejun Heo 11907d50b60bSTejun Heo return ahci_do_softreset(link, class, pmp, deadline); 1191a9cf5e85STejun Heo } 1192a9cf5e85STejun Heo 1193cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1194d4b2bab4STejun Heo unsigned long deadline) 1195c6fd2807SJeff Garzik { 1196cc0680a5STejun Heo struct ata_port *ap = link->ap; 1197c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1198c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1199c6fd2807SJeff Garzik struct ata_taskfile tf; 1200c6fd2807SJeff Garzik int rc; 1201c6fd2807SJeff Garzik 1202c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1203c6fd2807SJeff Garzik 12044447d351STejun Heo ahci_stop_engine(ap); 1205c6fd2807SJeff Garzik 1206c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1207cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1208dfd7a3dbSTejun Heo tf.command = 0x80; 12099977126cSTejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1210c6fd2807SJeff Garzik 1211cc0680a5STejun Heo rc = sata_std_hardreset(link, class, deadline); 1212c6fd2807SJeff Garzik 12134447d351STejun Heo ahci_start_engine(ap); 1214c6fd2807SJeff Garzik 1215cc0680a5STejun Heo if (rc == 0 && ata_link_online(link)) 1216c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 12177d50b60bSTejun Heo if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) 1218c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 1219c6fd2807SJeff Garzik 1220c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1221c6fd2807SJeff Garzik return rc; 1222c6fd2807SJeff Garzik } 1223c6fd2807SJeff Garzik 1224cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 1225d4b2bab4STejun Heo unsigned long deadline) 1226ad616ffbSTejun Heo { 1227cc0680a5STejun Heo struct ata_port *ap = link->ap; 1228da3dbb17STejun Heo u32 serror; 1229ad616ffbSTejun Heo int rc; 1230ad616ffbSTejun Heo 1231ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1232ad616ffbSTejun Heo 12334447d351STejun Heo ahci_stop_engine(ap); 1234ad616ffbSTejun Heo 1235cc0680a5STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 1236d4b2bab4STejun Heo deadline); 1237ad616ffbSTejun Heo 1238ad616ffbSTejun Heo /* vt8251 needs SError cleared for the port to operate */ 1239da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1240da3dbb17STejun Heo ahci_scr_write(ap, SCR_ERROR, serror); 1241ad616ffbSTejun Heo 12424447d351STejun Heo ahci_start_engine(ap); 1243ad616ffbSTejun Heo 1244ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1245ad616ffbSTejun Heo 1246ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1247ad616ffbSTejun Heo * request follow-up softreset. 1248ad616ffbSTejun Heo */ 1249ad616ffbSTejun Heo return rc ?: -EAGAIN; 1250ad616ffbSTejun Heo } 1251ad616ffbSTejun Heo 1252*edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 1253*edc93052STejun Heo unsigned long deadline) 1254*edc93052STejun Heo { 1255*edc93052STejun Heo struct ata_port *ap = link->ap; 1256*edc93052STejun Heo struct ahci_port_priv *pp = ap->private_data; 1257*edc93052STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1258*edc93052STejun Heo struct ata_taskfile tf; 1259*edc93052STejun Heo int rc; 1260*edc93052STejun Heo 1261*edc93052STejun Heo ahci_stop_engine(ap); 1262*edc93052STejun Heo 1263*edc93052STejun Heo /* clear D2H reception area to properly wait for D2H FIS */ 1264*edc93052STejun Heo ata_tf_init(link->device, &tf); 1265*edc93052STejun Heo tf.command = 0x80; 1266*edc93052STejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1267*edc93052STejun Heo 1268*edc93052STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 1269*edc93052STejun Heo deadline); 1270*edc93052STejun Heo 1271*edc93052STejun Heo ahci_start_engine(ap); 1272*edc93052STejun Heo 1273*edc93052STejun Heo if (rc || ata_link_offline(link)) 1274*edc93052STejun Heo return rc; 1275*edc93052STejun Heo 1276*edc93052STejun Heo /* spec mandates ">= 2ms" before checking status */ 1277*edc93052STejun Heo msleep(150); 1278*edc93052STejun Heo 1279*edc93052STejun Heo /* The pseudo configuration device on SIMG4726 attached to 1280*edc93052STejun Heo * ASUS P5W-DH Deluxe doesn't send signature FIS after 1281*edc93052STejun Heo * hardreset if no device is attached to the first downstream 1282*edc93052STejun Heo * port && the pseudo device locks up on SRST w/ PMP==0. To 1283*edc93052STejun Heo * work around this, wait for !BSY only briefly. If BSY isn't 1284*edc93052STejun Heo * cleared, perform CLO and proceed to IDENTIFY (achieved by 1285*edc93052STejun Heo * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA). 1286*edc93052STejun Heo * 1287*edc93052STejun Heo * Wait for two seconds. Devices attached to downstream port 1288*edc93052STejun Heo * which can't process the following IDENTIFY after this will 1289*edc93052STejun Heo * have to be reset again. For most cases, this should 1290*edc93052STejun Heo * suffice while making probing snappish enough. 1291*edc93052STejun Heo */ 1292*edc93052STejun Heo rc = ata_wait_ready(ap, jiffies + 2 * HZ); 1293*edc93052STejun Heo if (rc) 1294*edc93052STejun Heo ahci_kick_engine(ap, 0); 1295*edc93052STejun Heo 1296*edc93052STejun Heo return 0; 1297*edc93052STejun Heo } 1298*edc93052STejun Heo 1299cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class) 1300c6fd2807SJeff Garzik { 1301cc0680a5STejun Heo struct ata_port *ap = link->ap; 13024447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1303c6fd2807SJeff Garzik u32 new_tmp, tmp; 1304c6fd2807SJeff Garzik 1305cc0680a5STejun Heo ata_std_postreset(link, class); 1306c6fd2807SJeff Garzik 1307c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1308c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1309c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1310c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1311c6fd2807SJeff Garzik else 1312c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1313c6fd2807SJeff Garzik if (new_tmp != tmp) { 1314c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1315c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1316c6fd2807SJeff Garzik } 1317c6fd2807SJeff Garzik } 1318c6fd2807SJeff Garzik 13197d50b60bSTejun Heo static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, 13207d50b60bSTejun Heo unsigned long deadline) 13217d50b60bSTejun Heo { 13227d50b60bSTejun Heo return ahci_do_softreset(link, class, link->pmp, deadline); 13237d50b60bSTejun Heo } 13247d50b60bSTejun Heo 1325c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap) 1326c6fd2807SJeff Garzik { 13270d5ff566STejun Heo void __iomem *mmio = ap->ioaddr.cmd_addr; 1328c6fd2807SJeff Garzik 1329c6fd2807SJeff Garzik return readl(mmio + PORT_TFDATA) & 0xFF; 1330c6fd2807SJeff Garzik } 1331c6fd2807SJeff Garzik 1332c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 1333c6fd2807SJeff Garzik { 1334c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1335c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1336c6fd2807SJeff Garzik 1337c6fd2807SJeff Garzik ata_tf_from_fis(d2h_fis, tf); 1338c6fd2807SJeff Garzik } 1339c6fd2807SJeff Garzik 1340c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1341c6fd2807SJeff Garzik { 1342c6fd2807SJeff Garzik struct scatterlist *sg; 1343c6fd2807SJeff Garzik struct ahci_sg *ahci_sg; 1344c6fd2807SJeff Garzik unsigned int n_sg = 0; 1345c6fd2807SJeff Garzik 1346c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1347c6fd2807SJeff Garzik 1348c6fd2807SJeff Garzik /* 1349c6fd2807SJeff Garzik * Next, the S/G list. 1350c6fd2807SJeff Garzik */ 1351c6fd2807SJeff Garzik ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1352c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 1353c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1354c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1355c6fd2807SJeff Garzik 1356c6fd2807SJeff Garzik ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); 1357c6fd2807SJeff Garzik ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); 1358c6fd2807SJeff Garzik ahci_sg->flags_size = cpu_to_le32(sg_len - 1); 1359c6fd2807SJeff Garzik 1360c6fd2807SJeff Garzik ahci_sg++; 1361c6fd2807SJeff Garzik n_sg++; 1362c6fd2807SJeff Garzik } 1363c6fd2807SJeff Garzik 1364c6fd2807SJeff Garzik return n_sg; 1365c6fd2807SJeff Garzik } 1366c6fd2807SJeff Garzik 1367c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1368c6fd2807SJeff Garzik { 1369c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1370c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1371c6fd2807SJeff Garzik int is_atapi = is_atapi_taskfile(&qc->tf); 1372c6fd2807SJeff Garzik void *cmd_tbl; 1373c6fd2807SJeff Garzik u32 opts; 1374c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1375c6fd2807SJeff Garzik unsigned int n_elem; 1376c6fd2807SJeff Garzik 1377c6fd2807SJeff Garzik /* 1378c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1379c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1380c6fd2807SJeff Garzik */ 1381c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1382c6fd2807SJeff Garzik 13837d50b60bSTejun Heo ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); 1384c6fd2807SJeff Garzik if (is_atapi) { 1385c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1386c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1387c6fd2807SJeff Garzik } 1388c6fd2807SJeff Garzik 1389c6fd2807SJeff Garzik n_elem = 0; 1390c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1391c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1392c6fd2807SJeff Garzik 1393c6fd2807SJeff Garzik /* 1394c6fd2807SJeff Garzik * Fill in command slot information. 1395c6fd2807SJeff Garzik */ 13967d50b60bSTejun Heo opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); 1397c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1398c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1399c6fd2807SJeff Garzik if (is_atapi) 1400c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1401c6fd2807SJeff Garzik 1402c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1403c6fd2807SJeff Garzik } 1404c6fd2807SJeff Garzik 1405c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1406c6fd2807SJeff Garzik { 1407417a1a6dSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1408c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 14097d50b60bSTejun Heo struct ata_eh_info *host_ehi = &ap->link.eh_info; 14107d50b60bSTejun Heo struct ata_link *link = NULL; 14117d50b60bSTejun Heo struct ata_queued_cmd *active_qc; 14127d50b60bSTejun Heo struct ata_eh_info *active_ehi; 1413c6fd2807SJeff Garzik u32 serror; 1414c6fd2807SJeff Garzik 14157d50b60bSTejun Heo /* determine active link */ 14167d50b60bSTejun Heo ata_port_for_each_link(link, ap) 14177d50b60bSTejun Heo if (ata_link_active(link)) 14187d50b60bSTejun Heo break; 14197d50b60bSTejun Heo if (!link) 14207d50b60bSTejun Heo link = &ap->link; 14217d50b60bSTejun Heo 14227d50b60bSTejun Heo active_qc = ata_qc_from_tag(ap, link->active_tag); 14237d50b60bSTejun Heo active_ehi = &link->eh_info; 14247d50b60bSTejun Heo 14257d50b60bSTejun Heo /* record irq stat */ 14267d50b60bSTejun Heo ata_ehi_clear_desc(host_ehi); 14277d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); 1428c6fd2807SJeff Garzik 1429c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1430da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1431c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 14327d50b60bSTejun Heo host_ehi->serror |= serror; 1433c6fd2807SJeff Garzik 143441669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 1435417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) 143641669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 143741669553STejun Heo 143855a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 14397d50b60bSTejun Heo /* If qc is active, charge it; otherwise, the active 14407d50b60bSTejun Heo * link. There's no active qc on NCQ errors. It will 14417d50b60bSTejun Heo * be determined by EH by reading log page 10h. 14427d50b60bSTejun Heo */ 14437d50b60bSTejun Heo if (active_qc) 14447d50b60bSTejun Heo active_qc->err_mask |= AC_ERR_DEV; 14457d50b60bSTejun Heo else 14467d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_DEV; 14477d50b60bSTejun Heo 1448417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) 14497d50b60bSTejun Heo host_ehi->serror &= ~SERR_INTERNAL; 1450c6fd2807SJeff Garzik } 1451c6fd2807SJeff Garzik 1452c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1453c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1454c6fd2807SJeff Garzik 14557d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 14567d50b60bSTejun Heo active_ehi->action |= ATA_EH_SOFTRESET; 14577d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, 14587d50b60bSTejun Heo "unknown FIS %08x %08x %08x %08x" , 1459c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1460c6fd2807SJeff Garzik } 1461c6fd2807SJeff Garzik 14627d50b60bSTejun Heo if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { 14637d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 14647d50b60bSTejun Heo active_ehi->action |= ATA_EH_SOFTRESET; 14657d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, "incorrect PMP"); 14667d50b60bSTejun Heo } 1467c6fd2807SJeff Garzik 14687d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 14697d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_HOST_BUS; 14707d50b60bSTejun Heo host_ehi->action |= ATA_EH_SOFTRESET; 14717d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "host bus error"); 14727d50b60bSTejun Heo } 14737d50b60bSTejun Heo 14747d50b60bSTejun Heo if (irq_stat & PORT_IRQ_IF_ERR) { 14757d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_ATA_BUS; 14767d50b60bSTejun Heo host_ehi->action |= ATA_EH_SOFTRESET; 14777d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "interface fatal error"); 14787d50b60bSTejun Heo } 14797d50b60bSTejun Heo 14807d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 14817d50b60bSTejun Heo ata_ehi_hotplugged(host_ehi); 14827d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "%s", 14837d50b60bSTejun Heo irq_stat & PORT_IRQ_CONNECT ? 14847d50b60bSTejun Heo "connection status changed" : "PHY RDY changed"); 14857d50b60bSTejun Heo } 14867d50b60bSTejun Heo 14877d50b60bSTejun Heo /* okay, let's hand over to EH */ 1488c6fd2807SJeff Garzik 1489c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1490c6fd2807SJeff Garzik ata_port_freeze(ap); 1491c6fd2807SJeff Garzik else 1492c6fd2807SJeff Garzik ata_port_abort(ap); 1493c6fd2807SJeff Garzik } 1494c6fd2807SJeff Garzik 1495df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap) 1496c6fd2807SJeff Garzik { 14974447d351STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 14989af5c9c9STejun Heo struct ata_eh_info *ehi = &ap->link.eh_info; 14990291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 15005f226c6bSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1501b06ce3e5STejun Heo int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 1502c6fd2807SJeff Garzik u32 status, qc_active; 15030291f95fSTejun Heo int rc, known_irq = 0; 1504c6fd2807SJeff Garzik 1505c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1506c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1507c6fd2807SJeff Garzik 1508b06ce3e5STejun Heo /* ignore BAD_PMP while resetting */ 1509b06ce3e5STejun Heo if (unlikely(resetting)) 1510b06ce3e5STejun Heo status &= ~PORT_IRQ_BAD_PMP; 1511b06ce3e5STejun Heo 1512c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1513c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1514c6fd2807SJeff Garzik return; 1515c6fd2807SJeff Garzik } 1516c6fd2807SJeff Garzik 15172f294968SKristen Carlson Accardi if (status & PORT_IRQ_SDB_FIS) { 15185f226c6bSTejun Heo /* If SNotification is available, leave notification 15195f226c6bSTejun Heo * handling to sata_async_notification(). If not, 15205f226c6bSTejun Heo * emulate it by snooping SDB FIS RX area. 15215f226c6bSTejun Heo * 15225f226c6bSTejun Heo * Snooping FIS RX area is probably cheaper than 15235f226c6bSTejun Heo * poking SNotification but some constrollers which 15245f226c6bSTejun Heo * implement SNotification, ICH9 for example, don't 15255f226c6bSTejun Heo * store AN SDB FIS into receive area. 15265f226c6bSTejun Heo */ 15275f226c6bSTejun Heo if (hpriv->cap & HOST_CAP_SNTF) 15285f226c6bSTejun Heo sata_async_notification(ap); 15295f226c6bSTejun Heo else { 15305f226c6bSTejun Heo /* If the 'N' bit in word 0 of the FIS is set, 15315f226c6bSTejun Heo * we just received asynchronous notification. 15325f226c6bSTejun Heo * Tell libata about it. 15332f294968SKristen Carlson Accardi */ 15342f294968SKristen Carlson Accardi const __le32 *f = pp->rx_fis + RX_FIS_SDB; 15352f294968SKristen Carlson Accardi u32 f0 = le32_to_cpu(f[0]); 15362f294968SKristen Carlson Accardi 15377d77b247STejun Heo if (f0 & (1 << 15)) 15387d77b247STejun Heo sata_async_notification(ap); 15392f294968SKristen Carlson Accardi } 15405f226c6bSTejun Heo } 15412f294968SKristen Carlson Accardi 15427d50b60bSTejun Heo /* pp->active_link is valid iff any command is in flight */ 15437d50b60bSTejun Heo if (ap->qc_active && pp->active_link->sactive) 1544c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1545c6fd2807SJeff Garzik else 1546c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1547c6fd2807SJeff Garzik 1548c6fd2807SJeff Garzik rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1549b06ce3e5STejun Heo 1550b06ce3e5STejun Heo /* If resetting, spurious or invalid completions are expected, 1551b06ce3e5STejun Heo * return unconditionally. 1552b06ce3e5STejun Heo */ 1553b06ce3e5STejun Heo if (resetting) 1554b06ce3e5STejun Heo return; 1555b06ce3e5STejun Heo 1556c6fd2807SJeff Garzik if (rc > 0) 1557c6fd2807SJeff Garzik return; 1558c6fd2807SJeff Garzik if (rc < 0) { 1559c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1560c6fd2807SJeff Garzik ehi->action |= ATA_EH_SOFTRESET; 1561c6fd2807SJeff Garzik ata_port_freeze(ap); 1562c6fd2807SJeff Garzik return; 1563c6fd2807SJeff Garzik } 1564c6fd2807SJeff Garzik 15653a4fa0a2SRobert P. J. Day /* hmmm... a spurious interrupt */ 1566c6fd2807SJeff Garzik 15670291f95fSTejun Heo /* if !NCQ, ignore. No modern ATA device has broken HSM 15680291f95fSTejun Heo * implementation for non-NCQ commands. 15690291f95fSTejun Heo */ 15709af5c9c9STejun Heo if (!ap->link.sactive) 1571c6fd2807SJeff Garzik return; 1572c6fd2807SJeff Garzik 15730291f95fSTejun Heo if (status & PORT_IRQ_D2H_REG_FIS) { 15740291f95fSTejun Heo if (!pp->ncq_saw_d2h) 15750291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 15760291f95fSTejun Heo "D2H reg with I during NCQ, " 15770291f95fSTejun Heo "this message won't be printed again\n"); 15780291f95fSTejun Heo pp->ncq_saw_d2h = 1; 15790291f95fSTejun Heo known_irq = 1; 15800291f95fSTejun Heo } 1581c6fd2807SJeff Garzik 15820291f95fSTejun Heo if (status & PORT_IRQ_DMAS_FIS) { 15830291f95fSTejun Heo if (!pp->ncq_saw_dmas) 15840291f95fSTejun Heo ata_port_printk(ap, KERN_INFO, 15850291f95fSTejun Heo "DMAS FIS during NCQ, " 15860291f95fSTejun Heo "this message won't be printed again\n"); 15870291f95fSTejun Heo pp->ncq_saw_dmas = 1; 15880291f95fSTejun Heo known_irq = 1; 15890291f95fSTejun Heo } 15900291f95fSTejun Heo 1591a2bbd0c9STejun Heo if (status & PORT_IRQ_SDB_FIS) { 159204d4f7a1SAl Viro const __le32 *f = pp->rx_fis + RX_FIS_SDB; 15930291f95fSTejun Heo 1594afb2d552STejun Heo if (le32_to_cpu(f[1])) { 1595afb2d552STejun Heo /* SDB FIS containing spurious completions 1596afb2d552STejun Heo * might be dangerous, whine and fail commands 1597afb2d552STejun Heo * with HSM violation. EH will turn off NCQ 1598afb2d552STejun Heo * after several such failures. 1599afb2d552STejun Heo */ 1600afb2d552STejun Heo ata_ehi_push_desc(ehi, 1601afb2d552STejun Heo "spurious completions during NCQ " 1602a2bbd0c9STejun Heo "issue=0x%x SAct=0x%x FIS=%08x:%08x", 16030291f95fSTejun Heo readl(port_mmio + PORT_CMD_ISSUE), 16046096b63eSTejun Heo readl(port_mmio + PORT_SCR_ACT), 1605a2bbd0c9STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1606a2bbd0c9STejun Heo ehi->err_mask |= AC_ERR_HSM; 1607a2bbd0c9STejun Heo ehi->action |= ATA_EH_SOFTRESET; 1608a2bbd0c9STejun Heo ata_port_freeze(ap); 1609afb2d552STejun Heo } else { 1610afb2d552STejun Heo if (!pp->ncq_saw_sdb) 1611afb2d552STejun Heo ata_port_printk(ap, KERN_INFO, 1612afb2d552STejun Heo "spurious SDB FIS %08x:%08x during NCQ, " 1613afb2d552STejun Heo "this message won't be printed again\n", 1614afb2d552STejun Heo le32_to_cpu(f[0]), le32_to_cpu(f[1])); 1615afb2d552STejun Heo pp->ncq_saw_sdb = 1; 1616afb2d552STejun Heo } 16170291f95fSTejun Heo known_irq = 1; 16180291f95fSTejun Heo } 16190291f95fSTejun Heo 16200291f95fSTejun Heo if (!known_irq) 1621c6fd2807SJeff Garzik ata_port_printk(ap, KERN_INFO, "spurious interrupt " 16220291f95fSTejun Heo "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", 16239af5c9c9STejun Heo status, ap->link.active_tag, ap->link.sactive); 1624c6fd2807SJeff Garzik } 1625c6fd2807SJeff Garzik 1626c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap) 1627c6fd2807SJeff Garzik { 1628c6fd2807SJeff Garzik /* TODO */ 1629c6fd2807SJeff Garzik } 1630c6fd2807SJeff Garzik 16317d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1632c6fd2807SJeff Garzik { 1633cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1634c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1635c6fd2807SJeff Garzik unsigned int i, handled = 0; 1636c6fd2807SJeff Garzik void __iomem *mmio; 1637c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1638c6fd2807SJeff Garzik 1639c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1640c6fd2807SJeff Garzik 1641cca3974eSJeff Garzik hpriv = host->private_data; 16420d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 1643c6fd2807SJeff Garzik 1644c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1645c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1646c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1647c6fd2807SJeff Garzik if (!irq_stat) 1648c6fd2807SJeff Garzik return IRQ_NONE; 1649c6fd2807SJeff Garzik 1650cca3974eSJeff Garzik spin_lock(&host->lock); 1651c6fd2807SJeff Garzik 1652cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1653c6fd2807SJeff Garzik struct ata_port *ap; 1654c6fd2807SJeff Garzik 1655c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1656c6fd2807SJeff Garzik continue; 1657c6fd2807SJeff Garzik 1658cca3974eSJeff Garzik ap = host->ports[i]; 1659c6fd2807SJeff Garzik if (ap) { 1660df69c9c5SJeff Garzik ahci_port_intr(ap); 1661c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1662c6fd2807SJeff Garzik } else { 1663c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1664c6fd2807SJeff Garzik if (ata_ratelimit()) 1665cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1666c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1667c6fd2807SJeff Garzik } 1668c6fd2807SJeff Garzik 1669c6fd2807SJeff Garzik irq_ack |= (1 << i); 1670c6fd2807SJeff Garzik } 1671c6fd2807SJeff Garzik 1672c6fd2807SJeff Garzik if (irq_ack) { 1673c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1674c6fd2807SJeff Garzik handled = 1; 1675c6fd2807SJeff Garzik } 1676c6fd2807SJeff Garzik 1677cca3974eSJeff Garzik spin_unlock(&host->lock); 1678c6fd2807SJeff Garzik 1679c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1680c6fd2807SJeff Garzik 1681c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1682c6fd2807SJeff Garzik } 1683c6fd2807SJeff Garzik 1684c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1685c6fd2807SJeff Garzik { 1686c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 16874447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 16887d50b60bSTejun Heo struct ahci_port_priv *pp = ap->private_data; 16897d50b60bSTejun Heo 16907d50b60bSTejun Heo /* Keep track of the currently active link. It will be used 16917d50b60bSTejun Heo * in completion path to determine whether NCQ phase is in 16927d50b60bSTejun Heo * progress. 16937d50b60bSTejun Heo */ 16947d50b60bSTejun Heo pp->active_link = qc->dev->link; 1695c6fd2807SJeff Garzik 1696c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1697c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1698c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1699c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1700c6fd2807SJeff Garzik 1701c6fd2807SJeff Garzik return 0; 1702c6fd2807SJeff Garzik } 1703c6fd2807SJeff Garzik 1704c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1705c6fd2807SJeff Garzik { 17064447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1707c6fd2807SJeff Garzik 1708c6fd2807SJeff Garzik /* turn IRQ off */ 1709c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1710c6fd2807SJeff Garzik } 1711c6fd2807SJeff Garzik 1712c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1713c6fd2807SJeff Garzik { 17140d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 17154447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1716c6fd2807SJeff Garzik u32 tmp; 1717a7384925SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1718c6fd2807SJeff Garzik 1719c6fd2807SJeff Garzik /* clear IRQ */ 1720c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1721c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1722a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1723c6fd2807SJeff Garzik 17241c954a4dSTejun Heo /* turn IRQ back on */ 17251c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 1726c6fd2807SJeff Garzik } 1727c6fd2807SJeff Garzik 1728c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1729c6fd2807SJeff Garzik { 1730c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1731c6fd2807SJeff Garzik /* restart engine */ 17324447d351STejun Heo ahci_stop_engine(ap); 17334447d351STejun Heo ahci_start_engine(ap); 1734c6fd2807SJeff Garzik } 1735c6fd2807SJeff Garzik 1736c6fd2807SJeff Garzik /* perform recovery */ 17377d50b60bSTejun Heo sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, 17387d50b60bSTejun Heo ahci_hardreset, ahci_postreset, 17397d50b60bSTejun Heo sata_pmp_std_prereset, ahci_pmp_softreset, 17407d50b60bSTejun Heo sata_pmp_std_hardreset, sata_pmp_std_postreset); 1741c6fd2807SJeff Garzik } 1742c6fd2807SJeff Garzik 1743ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap) 1744ad616ffbSTejun Heo { 1745ad616ffbSTejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1746ad616ffbSTejun Heo /* restart engine */ 17474447d351STejun Heo ahci_stop_engine(ap); 17484447d351STejun Heo ahci_start_engine(ap); 1749ad616ffbSTejun Heo } 1750ad616ffbSTejun Heo 1751ad616ffbSTejun Heo /* perform recovery */ 1752ad616ffbSTejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, 1753ad616ffbSTejun Heo ahci_postreset); 1754ad616ffbSTejun Heo } 1755ad616ffbSTejun Heo 1756*edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap) 1757*edc93052STejun Heo { 1758*edc93052STejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1759*edc93052STejun Heo /* restart engine */ 1760*edc93052STejun Heo ahci_stop_engine(ap); 1761*edc93052STejun Heo ahci_start_engine(ap); 1762*edc93052STejun Heo } 1763*edc93052STejun Heo 1764*edc93052STejun Heo /* perform recovery */ 1765*edc93052STejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset, 1766*edc93052STejun Heo ahci_postreset); 1767*edc93052STejun Heo } 1768*edc93052STejun Heo 1769c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1770c6fd2807SJeff Garzik { 1771c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1772c6fd2807SJeff Garzik 1773c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1774d2e75dffSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) 1775d2e75dffSTejun Heo ahci_kick_engine(ap, 1); 1776c6fd2807SJeff Garzik } 1777c6fd2807SJeff Garzik 17787d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap) 17797d50b60bSTejun Heo { 17807d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 17811c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 17827d50b60bSTejun Heo u32 cmd; 17837d50b60bSTejun Heo 17847d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 17857d50b60bSTejun Heo cmd |= PORT_CMD_PMP; 17867d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 17871c954a4dSTejun Heo 17881c954a4dSTejun Heo pp->intr_mask |= PORT_IRQ_BAD_PMP; 17891c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 17907d50b60bSTejun Heo } 17917d50b60bSTejun Heo 17927d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap) 17937d50b60bSTejun Heo { 17947d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 17951c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 17967d50b60bSTejun Heo u32 cmd; 17977d50b60bSTejun Heo 17987d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 17997d50b60bSTejun Heo cmd &= ~PORT_CMD_PMP; 18007d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 18011c954a4dSTejun Heo 18021c954a4dSTejun Heo pp->intr_mask &= ~PORT_IRQ_BAD_PMP; 18031c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 18047d50b60bSTejun Heo } 18057d50b60bSTejun Heo 1806028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap) 1807028a2596SAlexey Dobriyan { 1808028a2596SAlexey Dobriyan ahci_power_up(ap); 1809028a2596SAlexey Dobriyan ahci_start_port(ap); 1810028a2596SAlexey Dobriyan 18117d50b60bSTejun Heo if (ap->nr_pmp_links) 18127d50b60bSTejun Heo ahci_pmp_attach(ap); 18137d50b60bSTejun Heo else 18147d50b60bSTejun Heo ahci_pmp_detach(ap); 18157d50b60bSTejun Heo 1816028a2596SAlexey Dobriyan return 0; 1817028a2596SAlexey Dobriyan } 1818028a2596SAlexey Dobriyan 1819438ac6d5STejun Heo #ifdef CONFIG_PM 1820c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1821c6fd2807SJeff Garzik { 1822c6fd2807SJeff Garzik const char *emsg = NULL; 1823c6fd2807SJeff Garzik int rc; 1824c6fd2807SJeff Garzik 18254447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 18268e16f941STejun Heo if (rc == 0) 18274447d351STejun Heo ahci_power_down(ap); 18288e16f941STejun Heo else { 1829c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1830df69c9c5SJeff Garzik ahci_start_port(ap); 1831c6fd2807SJeff Garzik } 1832c6fd2807SJeff Garzik 1833c6fd2807SJeff Garzik return rc; 1834c6fd2807SJeff Garzik } 1835c6fd2807SJeff Garzik 1836c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1837c6fd2807SJeff Garzik { 1838cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 18390d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1840c6fd2807SJeff Garzik u32 ctl; 1841c6fd2807SJeff Garzik 1842c6fd2807SJeff Garzik if (mesg.event == PM_EVENT_SUSPEND) { 1843c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1844c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1845c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1846c6fd2807SJeff Garzik */ 1847c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1848c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1849c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1850c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1851c6fd2807SJeff Garzik } 1852c6fd2807SJeff Garzik 1853c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1854c6fd2807SJeff Garzik } 1855c6fd2807SJeff Garzik 1856c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1857c6fd2807SJeff Garzik { 1858cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1859c6fd2807SJeff Garzik int rc; 1860c6fd2807SJeff Garzik 1861553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 1862553c4aa6STejun Heo if (rc) 1863553c4aa6STejun Heo return rc; 1864c6fd2807SJeff Garzik 1865c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 18664447d351STejun Heo rc = ahci_reset_controller(host); 1867c6fd2807SJeff Garzik if (rc) 1868c6fd2807SJeff Garzik return rc; 1869c6fd2807SJeff Garzik 18704447d351STejun Heo ahci_init_controller(host); 1871c6fd2807SJeff Garzik } 1872c6fd2807SJeff Garzik 1873cca3974eSJeff Garzik ata_host_resume(host); 1874c6fd2807SJeff Garzik 1875c6fd2807SJeff Garzik return 0; 1876c6fd2807SJeff Garzik } 1877438ac6d5STejun Heo #endif 1878c6fd2807SJeff Garzik 1879c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1880c6fd2807SJeff Garzik { 1881cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1882c6fd2807SJeff Garzik struct ahci_port_priv *pp; 1883c6fd2807SJeff Garzik void *mem; 1884c6fd2807SJeff Garzik dma_addr_t mem_dma; 1885c6fd2807SJeff Garzik int rc; 1886c6fd2807SJeff Garzik 188724dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 1888c6fd2807SJeff Garzik if (!pp) 1889c6fd2807SJeff Garzik return -ENOMEM; 1890c6fd2807SJeff Garzik 1891c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 189224dc5f33STejun Heo if (rc) 1893c6fd2807SJeff Garzik return rc; 1894c6fd2807SJeff Garzik 189524dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 189624dc5f33STejun Heo GFP_KERNEL); 189724dc5f33STejun Heo if (!mem) 1898c6fd2807SJeff Garzik return -ENOMEM; 1899c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1900c6fd2807SJeff Garzik 1901c6fd2807SJeff Garzik /* 1902c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1903c6fd2807SJeff Garzik * 32 bytes each in size 1904c6fd2807SJeff Garzik */ 1905c6fd2807SJeff Garzik pp->cmd_slot = mem; 1906c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 1907c6fd2807SJeff Garzik 1908c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 1909c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 1910c6fd2807SJeff Garzik 1911c6fd2807SJeff Garzik /* 1912c6fd2807SJeff Garzik * Second item: Received-FIS area 1913c6fd2807SJeff Garzik */ 1914c6fd2807SJeff Garzik pp->rx_fis = mem; 1915c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 1916c6fd2807SJeff Garzik 1917c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 1918c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 1919c6fd2807SJeff Garzik 1920c6fd2807SJeff Garzik /* 1921c6fd2807SJeff Garzik * Third item: data area for storing a single command 1922c6fd2807SJeff Garzik * and its scatter-gather table 1923c6fd2807SJeff Garzik */ 1924c6fd2807SJeff Garzik pp->cmd_tbl = mem; 1925c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 1926c6fd2807SJeff Garzik 1927a7384925SKristen Carlson Accardi /* 1928a7384925SKristen Carlson Accardi * Save off initial list of interrupts to be enabled. 1929a7384925SKristen Carlson Accardi * This could be changed later 1930a7384925SKristen Carlson Accardi */ 1931a7384925SKristen Carlson Accardi pp->intr_mask = DEF_PORT_IRQ; 1932a7384925SKristen Carlson Accardi 1933c6fd2807SJeff Garzik ap->private_data = pp; 1934c6fd2807SJeff Garzik 1935df69c9c5SJeff Garzik /* engage engines, captain */ 1936df69c9c5SJeff Garzik return ahci_port_resume(ap); 1937c6fd2807SJeff Garzik } 1938c6fd2807SJeff Garzik 1939c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 1940c6fd2807SJeff Garzik { 1941c6fd2807SJeff Garzik const char *emsg = NULL; 1942c6fd2807SJeff Garzik int rc; 1943c6fd2807SJeff Garzik 1944c6fd2807SJeff Garzik /* de-initialize port */ 19454447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1946c6fd2807SJeff Garzik if (rc) 1947c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 1948c6fd2807SJeff Garzik } 1949c6fd2807SJeff Garzik 19504447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 1951c6fd2807SJeff Garzik { 1952c6fd2807SJeff Garzik int rc; 1953c6fd2807SJeff Garzik 1954c6fd2807SJeff Garzik if (using_dac && 1955c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 1956c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 1957c6fd2807SJeff Garzik if (rc) { 1958c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1959c6fd2807SJeff Garzik if (rc) { 1960c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1961c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 1962c6fd2807SJeff Garzik return rc; 1963c6fd2807SJeff Garzik } 1964c6fd2807SJeff Garzik } 1965c6fd2807SJeff Garzik } else { 1966c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 1967c6fd2807SJeff Garzik if (rc) { 1968c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1969c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 1970c6fd2807SJeff Garzik return rc; 1971c6fd2807SJeff Garzik } 1972c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1973c6fd2807SJeff Garzik if (rc) { 1974c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1975c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 1976c6fd2807SJeff Garzik return rc; 1977c6fd2807SJeff Garzik } 1978c6fd2807SJeff Garzik } 1979c6fd2807SJeff Garzik return 0; 1980c6fd2807SJeff Garzik } 1981c6fd2807SJeff Garzik 19824447d351STejun Heo static void ahci_print_info(struct ata_host *host) 1983c6fd2807SJeff Garzik { 19844447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 19854447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 19864447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1987c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 1988c6fd2807SJeff Garzik const char *speed_s; 1989c6fd2807SJeff Garzik u16 cc; 1990c6fd2807SJeff Garzik const char *scc_s; 1991c6fd2807SJeff Garzik 1992c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 1993c6fd2807SJeff Garzik cap = hpriv->cap; 1994c6fd2807SJeff Garzik impl = hpriv->port_map; 1995c6fd2807SJeff Garzik 1996c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 1997c6fd2807SJeff Garzik if (speed == 1) 1998c6fd2807SJeff Garzik speed_s = "1.5"; 1999c6fd2807SJeff Garzik else if (speed == 2) 2000c6fd2807SJeff Garzik speed_s = "3"; 2001c6fd2807SJeff Garzik else 2002c6fd2807SJeff Garzik speed_s = "?"; 2003c6fd2807SJeff Garzik 2004c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 2005c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 2006c6fd2807SJeff Garzik scc_s = "IDE"; 2007c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 2008c6fd2807SJeff Garzik scc_s = "SATA"; 2009c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 2010c6fd2807SJeff Garzik scc_s = "RAID"; 2011c6fd2807SJeff Garzik else 2012c6fd2807SJeff Garzik scc_s = "unknown"; 2013c6fd2807SJeff Garzik 2014c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2015c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 2016c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 2017c6fd2807SJeff Garzik , 2018c6fd2807SJeff Garzik 2019c6fd2807SJeff Garzik (vers >> 24) & 0xff, 2020c6fd2807SJeff Garzik (vers >> 16) & 0xff, 2021c6fd2807SJeff Garzik (vers >> 8) & 0xff, 2022c6fd2807SJeff Garzik vers & 0xff, 2023c6fd2807SJeff Garzik 2024c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 2025c6fd2807SJeff Garzik (cap & 0x1f) + 1, 2026c6fd2807SJeff Garzik speed_s, 2027c6fd2807SJeff Garzik impl, 2028c6fd2807SJeff Garzik scc_s); 2029c6fd2807SJeff Garzik 2030c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2031c6fd2807SJeff Garzik "flags: " 2032203ef6c4STejun Heo "%s%s%s%s%s%s%s" 2033c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 2034c6fd2807SJeff Garzik , 2035c6fd2807SJeff Garzik 2036c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 2037c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 2038203ef6c4STejun Heo cap & (1 << 29) ? "sntf " : "", 2039c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 2040c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 2041c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 2042c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 2043c6fd2807SJeff Garzik 2044c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 2045c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 2046c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 2047c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 2048c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 2049c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 2050c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 2051c6fd2807SJeff Garzik ); 2052c6fd2807SJeff Garzik } 2053c6fd2807SJeff Garzik 2054*edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is 2055*edc93052STejun Heo * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't 2056*edc93052STejun Heo * support PMP and the 4726 either directly exports the device 2057*edc93052STejun Heo * attached to the first downstream port or acts as a hardware storage 2058*edc93052STejun Heo * controller and emulate a single ATA device (can be RAID 0/1 or some 2059*edc93052STejun Heo * other configuration). 2060*edc93052STejun Heo * 2061*edc93052STejun Heo * When there's no device attached to the first downstream port of the 2062*edc93052STejun Heo * 4726, "Config Disk" appears, which is a pseudo ATA device to 2063*edc93052STejun Heo * configure the 4726. However, ATA emulation of the device is very 2064*edc93052STejun Heo * lame. It doesn't send signature D2H Reg FIS after the initial 2065*edc93052STejun Heo * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. 2066*edc93052STejun Heo * 2067*edc93052STejun Heo * The following function works around the problem by always using 2068*edc93052STejun Heo * hardreset on the port and not depending on receiving signature FIS 2069*edc93052STejun Heo * afterward. If signature FIS isn't received soon, ATA class is 2070*edc93052STejun Heo * assumed without follow-up softreset. 2071*edc93052STejun Heo */ 2072*edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host) 2073*edc93052STejun Heo { 2074*edc93052STejun Heo static struct dmi_system_id sysids[] = { 2075*edc93052STejun Heo { 2076*edc93052STejun Heo .ident = "P5W DH Deluxe", 2077*edc93052STejun Heo .matches = { 2078*edc93052STejun Heo DMI_MATCH(DMI_SYS_VENDOR, 2079*edc93052STejun Heo "ASUSTEK COMPUTER INC"), 2080*edc93052STejun Heo DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), 2081*edc93052STejun Heo }, 2082*edc93052STejun Heo }, 2083*edc93052STejun Heo { } 2084*edc93052STejun Heo }; 2085*edc93052STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 2086*edc93052STejun Heo 2087*edc93052STejun Heo if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) && 2088*edc93052STejun Heo dmi_check_system(sysids)) { 2089*edc93052STejun Heo struct ata_port *ap = host->ports[1]; 2090*edc93052STejun Heo 2091*edc93052STejun Heo dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " 2092*edc93052STejun Heo "Deluxe on-board SIMG4726 workaround\n"); 2093*edc93052STejun Heo 2094*edc93052STejun Heo ap->ops = &ahci_p5wdh_ops; 2095*edc93052STejun Heo ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; 2096*edc93052STejun Heo } 2097*edc93052STejun Heo } 2098*edc93052STejun Heo 2099c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2100c6fd2807SJeff Garzik { 2101c6fd2807SJeff Garzik static int printed_version; 21024447d351STejun Heo struct ata_port_info pi = ahci_port_info[ent->driver_data]; 21034447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 210424dc5f33STejun Heo struct device *dev = &pdev->dev; 2105c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 21064447d351STejun Heo struct ata_host *host; 21074447d351STejun Heo int i, rc; 2108c6fd2807SJeff Garzik 2109c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2110c6fd2807SJeff Garzik 2111c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 2112c6fd2807SJeff Garzik 2113c6fd2807SJeff Garzik if (!printed_version++) 2114c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 2115c6fd2807SJeff Garzik 21164447d351STejun Heo /* acquire resources */ 211724dc5f33STejun Heo rc = pcim_enable_device(pdev); 2118c6fd2807SJeff Garzik if (rc) 2119c6fd2807SJeff Garzik return rc; 2120c6fd2807SJeff Garzik 21210d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 21220d5ff566STejun Heo if (rc == -EBUSY) 212324dc5f33STejun Heo pcim_pin_device(pdev); 21240d5ff566STejun Heo if (rc) 212524dc5f33STejun Heo return rc; 2126c6fd2807SJeff Garzik 212724dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 212824dc5f33STejun Heo if (!hpriv) 212924dc5f33STejun Heo return -ENOMEM; 2130417a1a6dSTejun Heo hpriv->flags |= (unsigned long)pi.private_data; 2131417a1a6dSTejun Heo 2132417a1a6dSTejun Heo if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) 2133417a1a6dSTejun Heo pci_intx(pdev, 1); 2134c6fd2807SJeff Garzik 21354447d351STejun Heo /* save initial config */ 2136417a1a6dSTejun Heo ahci_save_initial_config(pdev, hpriv); 2137c6fd2807SJeff Garzik 21384447d351STejun Heo /* prepare host */ 2139274c1fdeSTejun Heo if (hpriv->cap & HOST_CAP_NCQ) 21404447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 21414447d351STejun Heo 21427d50b60bSTejun Heo if (hpriv->cap & HOST_CAP_PMP) 21437d50b60bSTejun Heo pi.flags |= ATA_FLAG_PMP; 21447d50b60bSTejun Heo 21454447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); 21464447d351STejun Heo if (!host) 21474447d351STejun Heo return -ENOMEM; 21484447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 21494447d351STejun Heo host->private_data = hpriv; 21504447d351STejun Heo 21514447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 21524447d351STejun Heo struct ata_port *ap = host->ports[i]; 21534447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 21544447d351STejun Heo 2155cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); 2156cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, 2157cbcdd875STejun Heo 0x100 + ap->port_no * 0x80, "port"); 2158cbcdd875STejun Heo 2159dab632e8SJeff Garzik /* standard SATA port setup */ 2160203ef6c4STejun Heo if (hpriv->port_map & (1 << i)) 21614447d351STejun Heo ap->ioaddr.cmd_addr = port_mmio; 2162dab632e8SJeff Garzik 2163dab632e8SJeff Garzik /* disabled/not-implemented port */ 2164dab632e8SJeff Garzik else 2165dab632e8SJeff Garzik ap->ops = &ata_dummy_port_ops; 21664447d351STejun Heo } 2167c6fd2807SJeff Garzik 2168*edc93052STejun Heo /* apply workaround for ASUS P5W DH Deluxe mainboard */ 2169*edc93052STejun Heo ahci_p5wdh_workaround(host); 2170*edc93052STejun Heo 2171c6fd2807SJeff Garzik /* initialize adapter */ 21724447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2173c6fd2807SJeff Garzik if (rc) 217424dc5f33STejun Heo return rc; 2175c6fd2807SJeff Garzik 21764447d351STejun Heo rc = ahci_reset_controller(host); 21774447d351STejun Heo if (rc) 21784447d351STejun Heo return rc; 2179c6fd2807SJeff Garzik 21804447d351STejun Heo ahci_init_controller(host); 21814447d351STejun Heo ahci_print_info(host); 2182c6fd2807SJeff Garzik 21834447d351STejun Heo pci_set_master(pdev); 21844447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 21854447d351STejun Heo &ahci_sht); 2186c6fd2807SJeff Garzik } 2187c6fd2807SJeff Garzik 2188c6fd2807SJeff Garzik static int __init ahci_init(void) 2189c6fd2807SJeff Garzik { 2190c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 2191c6fd2807SJeff Garzik } 2192c6fd2807SJeff Garzik 2193c6fd2807SJeff Garzik static void __exit ahci_exit(void) 2194c6fd2807SJeff Garzik { 2195c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 2196c6fd2807SJeff Garzik } 2197c6fd2807SJeff Garzik 2198c6fd2807SJeff Garzik 2199c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 2200c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 2201c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2202c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 2203c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2204c6fd2807SJeff Garzik 2205c6fd2807SJeff Garzik module_init(ahci_init); 2206c6fd2807SJeff Garzik module_exit(ahci_exit); 2207