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> 44edc93052STejun 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 5231556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 5331556594SKristen Carlson Accardi enum link_pm policy); 5431556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap); 55c6fd2807SJeff Garzik 56c6fd2807SJeff Garzik enum { 57c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 58648a88beSTejun Heo AHCI_MAX_PORTS = 32, 59c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 60c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 61be5d8218SJens Axboe AHCI_USE_CLUSTERING = 1, 62c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 63c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 64c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 65c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 66c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 67c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 68c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 69c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 70c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 71c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 72c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 73c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 74c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 75c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 76c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 77c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 78c6fd2807SJeff Garzik 79c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 800291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 81c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 82c6fd2807SJeff Garzik 83c6fd2807SJeff Garzik board_ahci = 0, 847a234affSTejun Heo board_ahci_vt8251 = 1, 857a234affSTejun Heo board_ahci_ign_iferr = 2, 867a234affSTejun Heo board_ahci_sb600 = 3, 877a234affSTejun Heo board_ahci_mv = 4, 88c6fd2807SJeff Garzik 89c6fd2807SJeff Garzik /* global controller registers */ 90c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 91c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 92c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 93c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 94c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 95c6fd2807SJeff Garzik 96c6fd2807SJeff Garzik /* HOST_CTL bits */ 97c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 98c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 99c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 100c6fd2807SJeff Garzik 101c6fd2807SJeff Garzik /* HOST_CAP bits */ 102c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 1037d50b60bSTejun Heo HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ 104c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 10531556594SKristen Carlson Accardi HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ 106c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 107203ef6c4STejun Heo HOST_CAP_SNTF = (1 << 29), /* SNotification register */ 108c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 109c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 110c6fd2807SJeff Garzik 111c6fd2807SJeff Garzik /* registers for each SATA port */ 112c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 113c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 114c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 115c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 116c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 117c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 118c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 119c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 120c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 121c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 122c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 123c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 124c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 125c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 126203ef6c4STejun Heo PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ 127c6fd2807SJeff Garzik 128c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 129c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 130c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 131c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 132c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 133c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 134c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 135c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 136c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 137c6fd2807SJeff Garzik 138c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 139c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 140c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 141c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 142c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 143c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 144c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 145c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 146c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 147c6fd2807SJeff Garzik 148c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 149c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 150c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 151c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 1527d50b60bSTejun Heo PORT_IRQ_UNK_FIS | 1537d50b60bSTejun Heo PORT_IRQ_BAD_PMP, 154c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 155c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 156c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 157c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 158c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 159c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 160c6fd2807SJeff Garzik 161c6fd2807SJeff Garzik /* PORT_CMD bits */ 16231556594SKristen Carlson Accardi PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ 16331556594SKristen Carlson Accardi PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ 164c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 1657d50b60bSTejun Heo PORT_CMD_PMP = (1 << 17), /* PMP attached */ 166c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 167c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 168c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 169c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 170c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 171c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 172c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 173c6fd2807SJeff Garzik 174c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 175c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 176c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 177c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 178c6fd2807SJeff Garzik 179417a1a6dSTejun Heo /* hpriv->flags bits */ 180417a1a6dSTejun Heo AHCI_HFLAG_NO_NCQ = (1 << 0), 181417a1a6dSTejun Heo AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ 182417a1a6dSTejun Heo AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ 183417a1a6dSTejun Heo AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ 184417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ 185417a1a6dSTejun Heo AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ 1866949b914STejun Heo AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ 18731556594SKristen Carlson Accardi AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ 188417a1a6dSTejun Heo 189c6fd2807SJeff Garzik /* ap->flags bits */ 1901188c0d8STejun Heo 1911188c0d8STejun Heo AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 1921188c0d8STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 19331556594SKristen Carlson Accardi ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | 19431556594SKristen Carlson Accardi ATA_FLAG_IPM, 1950c88758bSTejun Heo AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, 196c4f7792cSTejun Heo 197c4f7792cSTejun Heo ICH_MAP = 0x90, /* ICH MAP register */ 198c6fd2807SJeff Garzik }; 199c6fd2807SJeff Garzik 200c6fd2807SJeff Garzik struct ahci_cmd_hdr { 2014ca4e439SAl Viro __le32 opts; 2024ca4e439SAl Viro __le32 status; 2034ca4e439SAl Viro __le32 tbl_addr; 2044ca4e439SAl Viro __le32 tbl_addr_hi; 2054ca4e439SAl Viro __le32 reserved[4]; 206c6fd2807SJeff Garzik }; 207c6fd2807SJeff Garzik 208c6fd2807SJeff Garzik struct ahci_sg { 2094ca4e439SAl Viro __le32 addr; 2104ca4e439SAl Viro __le32 addr_hi; 2114ca4e439SAl Viro __le32 reserved; 2124ca4e439SAl Viro __le32 flags_size; 213c6fd2807SJeff Garzik }; 214c6fd2807SJeff Garzik 215c6fd2807SJeff Garzik struct ahci_host_priv { 216417a1a6dSTejun Heo unsigned int flags; /* AHCI_HFLAG_* */ 217d447df14STejun Heo u32 cap; /* cap to use */ 218d447df14STejun Heo u32 port_map; /* port map to use */ 219d447df14STejun Heo u32 saved_cap; /* saved initial cap */ 220d447df14STejun Heo u32 saved_port_map; /* saved initial port_map */ 221c6fd2807SJeff Garzik }; 222c6fd2807SJeff Garzik 223c6fd2807SJeff Garzik struct ahci_port_priv { 2247d50b60bSTejun Heo struct ata_link *active_link; 225c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 226c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 227c6fd2807SJeff Garzik void *cmd_tbl; 228c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 229c6fd2807SJeff Garzik void *rx_fis; 230c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2310291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2320291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2330291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 234afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 235a7384925SKristen Carlson Accardi u32 intr_mask; /* interrupts to enable */ 236c6fd2807SJeff Garzik }; 237c6fd2807SJeff Garzik 238da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); 239da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); 240c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 241c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 242c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap); 243c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 244c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 245c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 246c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 247c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap); 248c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 249c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 2507d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap); 2517d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap); 252c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 253ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap); 254edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap); 255c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 256df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 257dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); 258dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 259dab632e8SJeff Garzik u32 opts); 260438ac6d5STejun Heo #ifdef CONFIG_PM 261c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 262c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 263c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 264438ac6d5STejun Heo #endif 265c6fd2807SJeff Garzik 26631556594SKristen Carlson Accardi static struct class_device_attribute *ahci_shost_attrs[] = { 26731556594SKristen Carlson Accardi &class_device_attr_link_power_management_policy, 26831556594SKristen Carlson Accardi NULL 26931556594SKristen Carlson Accardi }; 27031556594SKristen Carlson Accardi 271c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 272c6fd2807SJeff Garzik .module = THIS_MODULE, 273c6fd2807SJeff Garzik .name = DRV_NAME, 274c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 275c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 276c6fd2807SJeff Garzik .change_queue_depth = ata_scsi_change_queue_depth, 277c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 278c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 279c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 280c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 281c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 282c6fd2807SJeff Garzik .use_clustering = AHCI_USE_CLUSTERING, 283c6fd2807SJeff Garzik .proc_name = DRV_NAME, 284c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 285c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 286c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 287c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 28831556594SKristen Carlson Accardi .shost_attrs = ahci_shost_attrs, 289c6fd2807SJeff Garzik }; 290c6fd2807SJeff Garzik 291c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = { 292c6fd2807SJeff Garzik .check_status = ahci_check_status, 293c6fd2807SJeff Garzik .check_altstatus = ahci_check_status, 294c6fd2807SJeff Garzik .dev_select = ata_noop_dev_select, 295c6fd2807SJeff Garzik 296c6fd2807SJeff Garzik .tf_read = ahci_tf_read, 297c6fd2807SJeff Garzik 2987d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 299c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 300c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 301c6fd2807SJeff Garzik 302c6fd2807SJeff Garzik .irq_clear = ahci_irq_clear, 303c6fd2807SJeff Garzik 304c6fd2807SJeff Garzik .scr_read = ahci_scr_read, 305c6fd2807SJeff Garzik .scr_write = ahci_scr_write, 306c6fd2807SJeff Garzik 307c6fd2807SJeff Garzik .freeze = ahci_freeze, 308c6fd2807SJeff Garzik .thaw = ahci_thaw, 309c6fd2807SJeff Garzik 310c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 311c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 312c6fd2807SJeff Garzik 3137d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3147d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3157d50b60bSTejun Heo 316438ac6d5STejun Heo #ifdef CONFIG_PM 317c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 318c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 319438ac6d5STejun Heo #endif 32031556594SKristen Carlson Accardi .enable_pm = ahci_enable_alpm, 32131556594SKristen Carlson Accardi .disable_pm = ahci_disable_alpm, 322c6fd2807SJeff Garzik 323c6fd2807SJeff Garzik .port_start = ahci_port_start, 324c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 325c6fd2807SJeff Garzik }; 326c6fd2807SJeff Garzik 327ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = { 328ad616ffbSTejun Heo .check_status = ahci_check_status, 329ad616ffbSTejun Heo .check_altstatus = ahci_check_status, 330ad616ffbSTejun Heo .dev_select = ata_noop_dev_select, 331ad616ffbSTejun Heo 332ad616ffbSTejun Heo .tf_read = ahci_tf_read, 333ad616ffbSTejun Heo 3347d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 335ad616ffbSTejun Heo .qc_prep = ahci_qc_prep, 336ad616ffbSTejun Heo .qc_issue = ahci_qc_issue, 337ad616ffbSTejun Heo 338ad616ffbSTejun Heo .irq_clear = ahci_irq_clear, 339ad616ffbSTejun Heo 340ad616ffbSTejun Heo .scr_read = ahci_scr_read, 341ad616ffbSTejun Heo .scr_write = ahci_scr_write, 342ad616ffbSTejun Heo 343ad616ffbSTejun Heo .freeze = ahci_freeze, 344ad616ffbSTejun Heo .thaw = ahci_thaw, 345ad616ffbSTejun Heo 346ad616ffbSTejun Heo .error_handler = ahci_vt8251_error_handler, 347ad616ffbSTejun Heo .post_internal_cmd = ahci_post_internal_cmd, 348ad616ffbSTejun Heo 3497d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3507d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3517d50b60bSTejun Heo 352438ac6d5STejun Heo #ifdef CONFIG_PM 353ad616ffbSTejun Heo .port_suspend = ahci_port_suspend, 354ad616ffbSTejun Heo .port_resume = ahci_port_resume, 355438ac6d5STejun Heo #endif 356ad616ffbSTejun Heo 357ad616ffbSTejun Heo .port_start = ahci_port_start, 358ad616ffbSTejun Heo .port_stop = ahci_port_stop, 359ad616ffbSTejun Heo }; 360ad616ffbSTejun Heo 361edc93052STejun Heo static const struct ata_port_operations ahci_p5wdh_ops = { 362edc93052STejun Heo .check_status = ahci_check_status, 363edc93052STejun Heo .check_altstatus = ahci_check_status, 364edc93052STejun Heo .dev_select = ata_noop_dev_select, 365edc93052STejun Heo 366edc93052STejun Heo .tf_read = ahci_tf_read, 367edc93052STejun Heo 368edc93052STejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 369edc93052STejun Heo .qc_prep = ahci_qc_prep, 370edc93052STejun Heo .qc_issue = ahci_qc_issue, 371edc93052STejun Heo 372edc93052STejun Heo .irq_clear = ahci_irq_clear, 373edc93052STejun Heo 374edc93052STejun Heo .scr_read = ahci_scr_read, 375edc93052STejun Heo .scr_write = ahci_scr_write, 376edc93052STejun Heo 377edc93052STejun Heo .freeze = ahci_freeze, 378edc93052STejun Heo .thaw = ahci_thaw, 379edc93052STejun Heo 380edc93052STejun Heo .error_handler = ahci_p5wdh_error_handler, 381edc93052STejun Heo .post_internal_cmd = ahci_post_internal_cmd, 382edc93052STejun Heo 383edc93052STejun Heo .pmp_attach = ahci_pmp_attach, 384edc93052STejun Heo .pmp_detach = ahci_pmp_detach, 385edc93052STejun Heo 386edc93052STejun Heo #ifdef CONFIG_PM 387edc93052STejun Heo .port_suspend = ahci_port_suspend, 388edc93052STejun Heo .port_resume = ahci_port_resume, 389edc93052STejun Heo #endif 390edc93052STejun Heo 391edc93052STejun Heo .port_start = ahci_port_start, 392edc93052STejun Heo .port_stop = ahci_port_stop, 393edc93052STejun Heo }; 394edc93052STejun Heo 395417a1a6dSTejun Heo #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 396417a1a6dSTejun Heo 397c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 398c6fd2807SJeff Garzik /* board_ahci */ 399c6fd2807SJeff Garzik { 4001188c0d8STejun Heo .flags = AHCI_FLAG_COMMON, 4010c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 402c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 403469248abSJeff Garzik .udma_mask = ATA_UDMA6, 404c6fd2807SJeff Garzik .port_ops = &ahci_ops, 405c6fd2807SJeff Garzik }, 406c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 407c6fd2807SJeff Garzik { 4086949b914STejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), 409417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 4100c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, 411c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 412469248abSJeff Garzik .udma_mask = ATA_UDMA6, 413ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 414c6fd2807SJeff Garzik }, 41541669553STejun Heo /* board_ahci_ign_iferr */ 41641669553STejun Heo { 417417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), 418417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 4190c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 42041669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 421469248abSJeff Garzik .udma_mask = ATA_UDMA6, 42241669553STejun Heo .port_ops = &ahci_ops, 42341669553STejun Heo }, 42455a61604SConke Hu /* board_ahci_sb600 */ 42555a61604SConke Hu { 426417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 4276949b914STejun Heo AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), 428417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 4290c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 43055a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 431469248abSJeff Garzik .udma_mask = ATA_UDMA6, 43255a61604SConke Hu .port_ops = &ahci_ops, 43355a61604SConke Hu }, 434cd70c266SJeff Garzik /* board_ahci_mv */ 435cd70c266SJeff Garzik { 436417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | 437417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA), 438cd70c266SJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 439417a1a6dSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 4400c88758bSTejun Heo .link_flags = AHCI_LFLAG_COMMON, 441cd70c266SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 442cd70c266SJeff Garzik .udma_mask = ATA_UDMA6, 443cd70c266SJeff Garzik .port_ops = &ahci_ops, 444cd70c266SJeff Garzik }, 445c6fd2807SJeff Garzik }; 446c6fd2807SJeff Garzik 447c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 448c6fd2807SJeff Garzik /* Intel */ 44954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 45054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 45154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 45254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 45354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 45482490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 45554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 45654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 45754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 45854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 4597a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ 4607a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ 4617a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ 4627a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ 4637a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ 4647a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ 4657a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ 4667a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ 4677a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ 4687a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ 4697a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ 4707a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ 4717a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ 4727a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ 4737a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ 4747a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ 4757a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ 476d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ 477d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ 47816ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ 47916ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ 480c6fd2807SJeff Garzik 481e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 482e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 483e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 484c6fd2807SJeff Garzik 485c6fd2807SJeff Garzik /* ATI */ 486c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 487c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */ 488c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */ 489c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */ 490c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */ 491c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */ 492c69c0892Shenry su { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */ 493c6fd2807SJeff Garzik 494c6fd2807SJeff Garzik /* VIA */ 49554bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 496bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 497c6fd2807SJeff Garzik 498c6fd2807SJeff Garzik /* NVIDIA */ 49954bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ 50054bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ 50154bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ 50254bb3a94SJeff Garzik { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ 5036fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ 5046fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ 5056fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ 5066fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ 5076fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 5086fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 5096fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 5106fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 511895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 512895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 513895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 514895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 515895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 516895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 517895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 518895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 5190522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */ 5200522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */ 5210522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */ 5220522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */ 5230522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */ 5240522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */ 5250522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */ 5260522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */ 5270522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */ 5280522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */ 5290522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */ 5300522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */ 5310522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */ 5320522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */ 5330522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */ 5340522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */ 5350522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */ 5360522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */ 5370522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */ 5380522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */ 5390522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */ 5400522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ 5410522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ 5420522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ 5436ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */ 5446ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */ 5456ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */ 5466ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */ 5477100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ 5487100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ 5497100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ 5507100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ 5517100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ 5527100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ 5537100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ 5547100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ 555c6fd2807SJeff Garzik 556c6fd2807SJeff Garzik /* SiS */ 55754bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 55854bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 55954bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 560c6fd2807SJeff Garzik 561cd70c266SJeff Garzik /* Marvell */ 562cd70c266SJeff Garzik { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ 563cd70c266SJeff Garzik 564415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 565415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 566c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 567415ae2b5SJeff Garzik 568c6fd2807SJeff Garzik { } /* terminate list */ 569c6fd2807SJeff Garzik }; 570c6fd2807SJeff Garzik 571c6fd2807SJeff Garzik 572c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 573c6fd2807SJeff Garzik .name = DRV_NAME, 574c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 575c6fd2807SJeff Garzik .probe = ahci_init_one, 57624dc5f33STejun Heo .remove = ata_pci_remove_one, 577438ac6d5STejun Heo #ifdef CONFIG_PM 578c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 579c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 580438ac6d5STejun Heo #endif 581c6fd2807SJeff Garzik }; 582c6fd2807SJeff Garzik 583c6fd2807SJeff Garzik 58498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 58598fa4b60STejun Heo { 58698fa4b60STejun Heo return (cap & 0x1f) + 1; 58798fa4b60STejun Heo } 58898fa4b60STejun Heo 589dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host, 590dab632e8SJeff Garzik unsigned int port_no) 591dab632e8SJeff Garzik { 592dab632e8SJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 593dab632e8SJeff Garzik 594dab632e8SJeff Garzik return mmio + 0x100 + (port_no * 0x80); 595dab632e8SJeff Garzik } 596dab632e8SJeff Garzik 5974447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 598c6fd2807SJeff Garzik { 599dab632e8SJeff Garzik return __ahci_port_base(ap->host, ap->port_no); 600c6fd2807SJeff Garzik } 601c6fd2807SJeff Garzik 602b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio) 603b710a1f4STejun Heo { 604b710a1f4STejun Heo u32 tmp; 605b710a1f4STejun Heo 606b710a1f4STejun Heo /* turn on AHCI_EN */ 607b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 608b710a1f4STejun Heo if (!(tmp & HOST_AHCI_EN)) { 609b710a1f4STejun Heo tmp |= HOST_AHCI_EN; 610b710a1f4STejun Heo writel(tmp, mmio + HOST_CTL); 611b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ 612b710a1f4STejun Heo WARN_ON(!(tmp & HOST_AHCI_EN)); 613b710a1f4STejun Heo } 614b710a1f4STejun Heo } 615b710a1f4STejun Heo 616d447df14STejun Heo /** 617d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 6184447d351STejun Heo * @pdev: target PCI device 6194447d351STejun Heo * @hpriv: host private area to store config values 620d447df14STejun Heo * 621d447df14STejun Heo * Some registers containing configuration info might be setup by 622d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 623d447df14STejun Heo * initial values of those registers into @hpriv such that they 624d447df14STejun Heo * can be restored after controller reset. 625d447df14STejun Heo * 626d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 627d447df14STejun Heo * 628d447df14STejun Heo * LOCKING: 629d447df14STejun Heo * None. 630d447df14STejun Heo */ 6314447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 6324447d351STejun Heo struct ahci_host_priv *hpriv) 633d447df14STejun Heo { 6344447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 635d447df14STejun Heo u32 cap, port_map; 63617199b18STejun Heo int i; 637d447df14STejun Heo 638b710a1f4STejun Heo /* make sure AHCI mode is enabled before accessing CAP */ 639b710a1f4STejun Heo ahci_enable_ahci(mmio); 640b710a1f4STejun Heo 641d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 642d447df14STejun Heo * reset. Values without are used for driver operation. 643d447df14STejun Heo */ 644d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 645d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 646d447df14STejun Heo 647274c1fdeSTejun Heo /* some chips have errata preventing 64bit use */ 648417a1a6dSTejun Heo if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { 649c7a42156STejun Heo dev_printk(KERN_INFO, &pdev->dev, 650c7a42156STejun Heo "controller can't do 64bit DMA, forcing 32bit\n"); 651c7a42156STejun Heo cap &= ~HOST_CAP_64; 652c7a42156STejun Heo } 653c7a42156STejun Heo 654417a1a6dSTejun Heo if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { 655274c1fdeSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 656274c1fdeSTejun Heo "controller can't do NCQ, turning off CAP_NCQ\n"); 657274c1fdeSTejun Heo cap &= ~HOST_CAP_NCQ; 658274c1fdeSTejun Heo } 659274c1fdeSTejun Heo 6606949b914STejun Heo if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { 6616949b914STejun Heo dev_printk(KERN_INFO, &pdev->dev, 6626949b914STejun Heo "controller can't do PMP, turning off CAP_PMP\n"); 6636949b914STejun Heo cap &= ~HOST_CAP_PMP; 6646949b914STejun Heo } 6656949b914STejun Heo 666cd70c266SJeff Garzik /* 667cd70c266SJeff Garzik * Temporary Marvell 6145 hack: PATA port presence 668cd70c266SJeff Garzik * is asserted through the standard AHCI port 669cd70c266SJeff Garzik * presence register, as bit 4 (counting from 0) 670cd70c266SJeff Garzik */ 671417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 672cd70c266SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 673cd70c266SJeff Garzik "MV_AHCI HACK: port_map %x -> %x\n", 674cd70c266SJeff Garzik hpriv->port_map, 675cd70c266SJeff Garzik hpriv->port_map & 0xf); 676cd70c266SJeff Garzik 677cd70c266SJeff Garzik port_map &= 0xf; 678cd70c266SJeff Garzik } 679cd70c266SJeff Garzik 68017199b18STejun Heo /* cross check port_map and cap.n_ports */ 6817a234affSTejun Heo if (port_map) { 682*837f5f8fSTejun Heo int map_ports = 0; 68317199b18STejun Heo 684*837f5f8fSTejun Heo for (i = 0; i < AHCI_MAX_PORTS; i++) 685*837f5f8fSTejun Heo if (port_map & (1 << i)) 686*837f5f8fSTejun Heo map_ports++; 68717199b18STejun Heo 688*837f5f8fSTejun Heo /* If PI has more ports than n_ports, whine, clear 689*837f5f8fSTejun Heo * port_map and let it be generated from n_ports. 69017199b18STejun Heo */ 691*837f5f8fSTejun Heo if (map_ports > ahci_nr_ports(cap)) { 6924447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 693*837f5f8fSTejun Heo "implemented port map (0x%x) contains more " 694*837f5f8fSTejun Heo "ports than nr_ports (%u), using nr_ports\n", 695*837f5f8fSTejun Heo port_map, ahci_nr_ports(cap)); 6967a234affSTejun Heo port_map = 0; 6977a234affSTejun Heo } 6987a234affSTejun Heo } 6997a234affSTejun Heo 70017199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 7017a234affSTejun Heo if (!port_map) { 70217199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 7037a234affSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 7047a234affSTejun Heo "forcing PORTS_IMPL to 0x%x\n", port_map); 7057a234affSTejun Heo 7067a234affSTejun Heo /* write the fixed up value to the PI register */ 7077a234affSTejun Heo hpriv->saved_port_map = port_map; 70817199b18STejun Heo } 70917199b18STejun Heo 710d447df14STejun Heo /* record values to use during operation */ 711d447df14STejun Heo hpriv->cap = cap; 712d447df14STejun Heo hpriv->port_map = port_map; 713d447df14STejun Heo } 714d447df14STejun Heo 715d447df14STejun Heo /** 716d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 7174447d351STejun Heo * @host: target ATA host 718d447df14STejun Heo * 719d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 720d447df14STejun Heo * 721d447df14STejun Heo * LOCKING: 722d447df14STejun Heo * None. 723d447df14STejun Heo */ 7244447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 725d447df14STejun Heo { 7264447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 7274447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 7284447d351STejun Heo 729d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 730d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 731d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 732d447df14STejun Heo } 733d447df14STejun Heo 734203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) 735c6fd2807SJeff Garzik { 736203ef6c4STejun Heo static const int offset[] = { 737203ef6c4STejun Heo [SCR_STATUS] = PORT_SCR_STAT, 738203ef6c4STejun Heo [SCR_CONTROL] = PORT_SCR_CTL, 739203ef6c4STejun Heo [SCR_ERROR] = PORT_SCR_ERR, 740203ef6c4STejun Heo [SCR_ACTIVE] = PORT_SCR_ACT, 741203ef6c4STejun Heo [SCR_NOTIFICATION] = PORT_SCR_NTF, 742203ef6c4STejun Heo }; 743203ef6c4STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 744c6fd2807SJeff Garzik 745203ef6c4STejun Heo if (sc_reg < ARRAY_SIZE(offset) && 746203ef6c4STejun Heo (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) 747203ef6c4STejun Heo return offset[sc_reg]; 748da3dbb17STejun Heo return 0; 749c6fd2807SJeff Garzik } 750c6fd2807SJeff Garzik 751203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 752c6fd2807SJeff Garzik { 753203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 754203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 755c6fd2807SJeff Garzik 756203ef6c4STejun Heo if (offset) { 757203ef6c4STejun Heo *val = readl(port_mmio + offset); 758203ef6c4STejun Heo return 0; 759203ef6c4STejun Heo } 760da3dbb17STejun Heo return -EINVAL; 761c6fd2807SJeff Garzik } 762c6fd2807SJeff Garzik 763203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 764203ef6c4STejun Heo { 765203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 766203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 767203ef6c4STejun Heo 768203ef6c4STejun Heo if (offset) { 769203ef6c4STejun Heo writel(val, port_mmio + offset); 770da3dbb17STejun Heo return 0; 771c6fd2807SJeff Garzik } 772203ef6c4STejun Heo return -EINVAL; 773203ef6c4STejun Heo } 774c6fd2807SJeff Garzik 7754447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 776c6fd2807SJeff Garzik { 7774447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 778c6fd2807SJeff Garzik u32 tmp; 779c6fd2807SJeff Garzik 780c6fd2807SJeff Garzik /* start DMA */ 781c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 782c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 783c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 784c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 785c6fd2807SJeff Garzik } 786c6fd2807SJeff Garzik 7874447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 788c6fd2807SJeff Garzik { 7894447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 790c6fd2807SJeff Garzik u32 tmp; 791c6fd2807SJeff Garzik 792c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 793c6fd2807SJeff Garzik 794c6fd2807SJeff Garzik /* check if the HBA is idle */ 795c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 796c6fd2807SJeff Garzik return 0; 797c6fd2807SJeff Garzik 798c6fd2807SJeff Garzik /* setting HBA to idle */ 799c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 800c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 801c6fd2807SJeff Garzik 802c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 803c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 804c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 805c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 806c6fd2807SJeff Garzik return -EIO; 807c6fd2807SJeff Garzik 808c6fd2807SJeff Garzik return 0; 809c6fd2807SJeff Garzik } 810c6fd2807SJeff Garzik 8114447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 812c6fd2807SJeff Garzik { 8134447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 8144447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8154447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 816c6fd2807SJeff Garzik u32 tmp; 817c6fd2807SJeff Garzik 818c6fd2807SJeff Garzik /* set FIS registers */ 8194447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8204447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 8214447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 8224447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 823c6fd2807SJeff Garzik 8244447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8254447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 8264447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 8274447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 828c6fd2807SJeff Garzik 829c6fd2807SJeff Garzik /* enable FIS reception */ 830c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 831c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 832c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 833c6fd2807SJeff Garzik 834c6fd2807SJeff Garzik /* flush */ 835c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 836c6fd2807SJeff Garzik } 837c6fd2807SJeff Garzik 8384447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 839c6fd2807SJeff Garzik { 8404447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 841c6fd2807SJeff Garzik u32 tmp; 842c6fd2807SJeff Garzik 843c6fd2807SJeff Garzik /* disable FIS reception */ 844c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 845c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 846c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 847c6fd2807SJeff Garzik 848c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 849c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 850c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 851c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 852c6fd2807SJeff Garzik return -EBUSY; 853c6fd2807SJeff Garzik 854c6fd2807SJeff Garzik return 0; 855c6fd2807SJeff Garzik } 856c6fd2807SJeff Garzik 8574447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 858c6fd2807SJeff Garzik { 8594447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8604447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 861c6fd2807SJeff Garzik u32 cmd; 862c6fd2807SJeff Garzik 863c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 864c6fd2807SJeff Garzik 865c6fd2807SJeff Garzik /* spin up device */ 8664447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 867c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 868c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 869c6fd2807SJeff Garzik } 870c6fd2807SJeff Garzik 871c6fd2807SJeff Garzik /* wake up link */ 872c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 873c6fd2807SJeff Garzik } 874c6fd2807SJeff Garzik 87531556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap) 87631556594SKristen Carlson Accardi { 87731556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 87831556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 87931556594SKristen Carlson Accardi u32 cmd; 88031556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 88131556594SKristen Carlson Accardi 88231556594SKristen Carlson Accardi /* IPM bits should be disabled by libata-core */ 88331556594SKristen Carlson Accardi /* get the existing command bits */ 88431556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 88531556594SKristen Carlson Accardi 88631556594SKristen Carlson Accardi /* disable ALPM and ASP */ 88731556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ASP; 88831556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ALPE; 88931556594SKristen Carlson Accardi 89031556594SKristen Carlson Accardi /* force the interface back to active */ 89131556594SKristen Carlson Accardi cmd |= PORT_CMD_ICC_ACTIVE; 89231556594SKristen Carlson Accardi 89331556594SKristen Carlson Accardi /* write out new cmd value */ 89431556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 89531556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 89631556594SKristen Carlson Accardi 89731556594SKristen Carlson Accardi /* wait 10ms to be sure we've come out of any low power state */ 89831556594SKristen Carlson Accardi msleep(10); 89931556594SKristen Carlson Accardi 90031556594SKristen Carlson Accardi /* clear out any PhyRdy stuff from interrupt status */ 90131556594SKristen Carlson Accardi writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); 90231556594SKristen Carlson Accardi 90331556594SKristen Carlson Accardi /* go ahead and clean out PhyRdy Change from Serror too */ 90431556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 90531556594SKristen Carlson Accardi 90631556594SKristen Carlson Accardi /* 90731556594SKristen Carlson Accardi * Clear flag to indicate that we should ignore all PhyRdy 90831556594SKristen Carlson Accardi * state changes 90931556594SKristen Carlson Accardi */ 91031556594SKristen Carlson Accardi hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; 91131556594SKristen Carlson Accardi 91231556594SKristen Carlson Accardi /* 91331556594SKristen Carlson Accardi * Enable interrupts on Phy Ready. 91431556594SKristen Carlson Accardi */ 91531556594SKristen Carlson Accardi pp->intr_mask |= PORT_IRQ_PHYRDY; 91631556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 91731556594SKristen Carlson Accardi 91831556594SKristen Carlson Accardi /* 91931556594SKristen Carlson Accardi * don't change the link pm policy - we can be called 92031556594SKristen Carlson Accardi * just to turn of link pm temporarily 92131556594SKristen Carlson Accardi */ 92231556594SKristen Carlson Accardi } 92331556594SKristen Carlson Accardi 92431556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 92531556594SKristen Carlson Accardi enum link_pm policy) 92631556594SKristen Carlson Accardi { 92731556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 92831556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 92931556594SKristen Carlson Accardi u32 cmd; 93031556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 93131556594SKristen Carlson Accardi u32 asp; 93231556594SKristen Carlson Accardi 93331556594SKristen Carlson Accardi /* Make sure the host is capable of link power management */ 93431556594SKristen Carlson Accardi if (!(hpriv->cap & HOST_CAP_ALPM)) 93531556594SKristen Carlson Accardi return -EINVAL; 93631556594SKristen Carlson Accardi 93731556594SKristen Carlson Accardi switch (policy) { 93831556594SKristen Carlson Accardi case MAX_PERFORMANCE: 93931556594SKristen Carlson Accardi case NOT_AVAILABLE: 94031556594SKristen Carlson Accardi /* 94131556594SKristen Carlson Accardi * if we came here with NOT_AVAILABLE, 94231556594SKristen Carlson Accardi * it just means this is the first time we 94331556594SKristen Carlson Accardi * have tried to enable - default to max performance, 94431556594SKristen Carlson Accardi * and let the user go to lower power modes on request. 94531556594SKristen Carlson Accardi */ 94631556594SKristen Carlson Accardi ahci_disable_alpm(ap); 94731556594SKristen Carlson Accardi return 0; 94831556594SKristen Carlson Accardi case MIN_POWER: 94931556594SKristen Carlson Accardi /* configure HBA to enter SLUMBER */ 95031556594SKristen Carlson Accardi asp = PORT_CMD_ASP; 95131556594SKristen Carlson Accardi break; 95231556594SKristen Carlson Accardi case MEDIUM_POWER: 95331556594SKristen Carlson Accardi /* configure HBA to enter PARTIAL */ 95431556594SKristen Carlson Accardi asp = 0; 95531556594SKristen Carlson Accardi break; 95631556594SKristen Carlson Accardi default: 95731556594SKristen Carlson Accardi return -EINVAL; 95831556594SKristen Carlson Accardi } 95931556594SKristen Carlson Accardi 96031556594SKristen Carlson Accardi /* 96131556594SKristen Carlson Accardi * Disable interrupts on Phy Ready. This keeps us from 96231556594SKristen Carlson Accardi * getting woken up due to spurious phy ready interrupts 96331556594SKristen Carlson Accardi * TBD - Hot plug should be done via polling now, is 96431556594SKristen Carlson Accardi * that even supported? 96531556594SKristen Carlson Accardi */ 96631556594SKristen Carlson Accardi pp->intr_mask &= ~PORT_IRQ_PHYRDY; 96731556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 96831556594SKristen Carlson Accardi 96931556594SKristen Carlson Accardi /* 97031556594SKristen Carlson Accardi * Set a flag to indicate that we should ignore all PhyRdy 97131556594SKristen Carlson Accardi * state changes since these can happen now whenever we 97231556594SKristen Carlson Accardi * change link state 97331556594SKristen Carlson Accardi */ 97431556594SKristen Carlson Accardi hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; 97531556594SKristen Carlson Accardi 97631556594SKristen Carlson Accardi /* get the existing command bits */ 97731556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 97831556594SKristen Carlson Accardi 97931556594SKristen Carlson Accardi /* 98031556594SKristen Carlson Accardi * Set ASP based on Policy 98131556594SKristen Carlson Accardi */ 98231556594SKristen Carlson Accardi cmd |= asp; 98331556594SKristen Carlson Accardi 98431556594SKristen Carlson Accardi /* 98531556594SKristen Carlson Accardi * Setting this bit will instruct the HBA to aggressively 98631556594SKristen Carlson Accardi * enter a lower power link state when it's appropriate and 98731556594SKristen Carlson Accardi * based on the value set above for ASP 98831556594SKristen Carlson Accardi */ 98931556594SKristen Carlson Accardi cmd |= PORT_CMD_ALPE; 99031556594SKristen Carlson Accardi 99131556594SKristen Carlson Accardi /* write out new cmd value */ 99231556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 99331556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 99431556594SKristen Carlson Accardi 99531556594SKristen Carlson Accardi /* IPM bits should be set by libata-core */ 99631556594SKristen Carlson Accardi return 0; 99731556594SKristen Carlson Accardi } 99831556594SKristen Carlson Accardi 999438ac6d5STejun Heo #ifdef CONFIG_PM 10004447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 1001c6fd2807SJeff Garzik { 10024447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 10034447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1004c6fd2807SJeff Garzik u32 cmd, scontrol; 1005c6fd2807SJeff Garzik 10064447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 100707c53dacSTejun Heo return; 1008c6fd2807SJeff Garzik 100907c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 1010c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 1011c6fd2807SJeff Garzik scontrol &= ~0xf; 1012c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 1013c6fd2807SJeff Garzik 1014c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 101507c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 1016c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 1017c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 1018c6fd2807SJeff Garzik } 1019438ac6d5STejun Heo #endif 1020c6fd2807SJeff Garzik 1021df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap) 1022c6fd2807SJeff Garzik { 1023c6fd2807SJeff Garzik /* enable FIS reception */ 10244447d351STejun Heo ahci_start_fis_rx(ap); 1025c6fd2807SJeff Garzik 1026c6fd2807SJeff Garzik /* enable DMA */ 10274447d351STejun Heo ahci_start_engine(ap); 1028c6fd2807SJeff Garzik } 1029c6fd2807SJeff Garzik 10304447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 1031c6fd2807SJeff Garzik { 1032c6fd2807SJeff Garzik int rc; 1033c6fd2807SJeff Garzik 1034c6fd2807SJeff Garzik /* disable DMA */ 10354447d351STejun Heo rc = ahci_stop_engine(ap); 1036c6fd2807SJeff Garzik if (rc) { 1037c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 1038c6fd2807SJeff Garzik return rc; 1039c6fd2807SJeff Garzik } 1040c6fd2807SJeff Garzik 1041c6fd2807SJeff Garzik /* disable FIS reception */ 10424447d351STejun Heo rc = ahci_stop_fis_rx(ap); 1043c6fd2807SJeff Garzik if (rc) { 1044c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 1045c6fd2807SJeff Garzik return rc; 1046c6fd2807SJeff Garzik } 1047c6fd2807SJeff Garzik 1048c6fd2807SJeff Garzik return 0; 1049c6fd2807SJeff Garzik } 1050c6fd2807SJeff Garzik 10514447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 1052c6fd2807SJeff Garzik { 10534447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 105449f29090STejun Heo struct ahci_host_priv *hpriv = host->private_data; 10554447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1056d447df14STejun Heo u32 tmp; 1057c6fd2807SJeff Garzik 10583cc3eb11SJeff Garzik /* we must be in AHCI mode, before using anything 10593cc3eb11SJeff Garzik * AHCI-specific, such as HOST_RESET. 10603cc3eb11SJeff Garzik */ 1061b710a1f4STejun Heo ahci_enable_ahci(mmio); 10623cc3eb11SJeff Garzik 10633cc3eb11SJeff Garzik /* global controller reset */ 1064b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 1065c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 1066c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 1067c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1068c6fd2807SJeff Garzik } 1069c6fd2807SJeff Garzik 1070c6fd2807SJeff Garzik /* reset must complete within 1 second, or 1071c6fd2807SJeff Garzik * the hardware should be considered fried. 1072c6fd2807SJeff Garzik */ 1073c6fd2807SJeff Garzik ssleep(1); 1074c6fd2807SJeff Garzik 1075c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1076c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 10774447d351STejun Heo dev_printk(KERN_ERR, host->dev, 1078c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 1079c6fd2807SJeff Garzik return -EIO; 1080c6fd2807SJeff Garzik } 1081c6fd2807SJeff Garzik 108298fa4b60STejun Heo /* turn on AHCI mode */ 1083b710a1f4STejun Heo ahci_enable_ahci(mmio); 108498fa4b60STejun Heo 1085d447df14STejun Heo /* some registers might be cleared on reset. restore initial values */ 10864447d351STejun Heo ahci_restore_initial_config(host); 1087c6fd2807SJeff Garzik 1088c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 1089c6fd2807SJeff Garzik u16 tmp16; 1090c6fd2807SJeff Garzik 1091c6fd2807SJeff Garzik /* configure PCS */ 1092c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 109349f29090STejun Heo if ((tmp16 & hpriv->port_map) != hpriv->port_map) { 109449f29090STejun Heo tmp16 |= hpriv->port_map; 1095c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 1096c6fd2807SJeff Garzik } 109749f29090STejun Heo } 1098c6fd2807SJeff Garzik 1099c6fd2807SJeff Garzik return 0; 1100c6fd2807SJeff Garzik } 1101c6fd2807SJeff Garzik 11022bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, 11032bcd866bSJeff Garzik int port_no, void __iomem *mmio, 11042bcd866bSJeff Garzik void __iomem *port_mmio) 1105c6fd2807SJeff Garzik { 1106c6fd2807SJeff Garzik const char *emsg = NULL; 11072bcd866bSJeff Garzik int rc; 11082bcd866bSJeff Garzik u32 tmp; 1109c6fd2807SJeff Garzik 1110c6fd2807SJeff Garzik /* make sure port is not active */ 11114447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1112c6fd2807SJeff Garzik if (rc) 1113c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 1114c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 1115c6fd2807SJeff Garzik 1116c6fd2807SJeff Garzik /* clear SError */ 1117c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 1118c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 1119c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 1120c6fd2807SJeff Garzik 1121c6fd2807SJeff Garzik /* clear port IRQ */ 1122c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1123c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1124c6fd2807SJeff Garzik if (tmp) 1125c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1126c6fd2807SJeff Garzik 11272bcd866bSJeff Garzik writel(1 << port_no, mmio + HOST_IRQ_STAT); 11282bcd866bSJeff Garzik } 11292bcd866bSJeff Garzik 11302bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host) 11312bcd866bSJeff Garzik { 1132417a1a6dSTejun Heo struct ahci_host_priv *hpriv = host->private_data; 11332bcd866bSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 11342bcd866bSJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 11352bcd866bSJeff Garzik int i; 1136cd70c266SJeff Garzik void __iomem *port_mmio; 11372bcd866bSJeff Garzik u32 tmp; 11382bcd866bSJeff Garzik 1139417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 1140cd70c266SJeff Garzik port_mmio = __ahci_port_base(host, 4); 1141cd70c266SJeff Garzik 1142cd70c266SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1143cd70c266SJeff Garzik 1144cd70c266SJeff Garzik /* clear port IRQ */ 1145cd70c266SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1146cd70c266SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1147cd70c266SJeff Garzik if (tmp) 1148cd70c266SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1149cd70c266SJeff Garzik } 1150cd70c266SJeff Garzik 11512bcd866bSJeff Garzik for (i = 0; i < host->n_ports; i++) { 11522bcd866bSJeff Garzik struct ata_port *ap = host->ports[i]; 11532bcd866bSJeff Garzik 1154cd70c266SJeff Garzik port_mmio = ahci_port_base(ap); 11552bcd866bSJeff Garzik if (ata_port_is_dummy(ap)) 11562bcd866bSJeff Garzik continue; 11572bcd866bSJeff Garzik 11582bcd866bSJeff Garzik ahci_port_init(pdev, ap, i, mmio, port_mmio); 1159c6fd2807SJeff Garzik } 1160c6fd2807SJeff Garzik 1161c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1162c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1163c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 1164c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1165c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1166c6fd2807SJeff Garzik } 1167c6fd2807SJeff Garzik 1168c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 1169c6fd2807SJeff Garzik { 11704447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1171c6fd2807SJeff Garzik struct ata_taskfile tf; 1172c6fd2807SJeff Garzik u32 tmp; 1173c6fd2807SJeff Garzik 1174c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 1175c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 1176c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 1177c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 1178c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 1179c6fd2807SJeff Garzik 1180c6fd2807SJeff Garzik return ata_dev_classify(&tf); 1181c6fd2807SJeff Garzik } 1182c6fd2807SJeff Garzik 1183c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 1184c6fd2807SJeff Garzik u32 opts) 1185c6fd2807SJeff Garzik { 1186c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 1187c6fd2807SJeff Garzik 1188c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 1189c6fd2807SJeff Garzik 1190c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 1191c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 1192c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 1193c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 1194c6fd2807SJeff Garzik } 1195c6fd2807SJeff Garzik 1196d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart) 1197c6fd2807SJeff Garzik { 11980d5ff566STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 1199cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1200c6fd2807SJeff Garzik u32 tmp; 1201d2e75dffSTejun Heo int busy, rc; 1202c6fd2807SJeff Garzik 1203d2e75dffSTejun Heo /* do we need to kick the port? */ 1204d2e75dffSTejun Heo busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ); 1205d2e75dffSTejun Heo if (!busy && !force_restart) 1206d2e75dffSTejun Heo return 0; 1207c6fd2807SJeff Garzik 1208d2e75dffSTejun Heo /* stop engine */ 1209d2e75dffSTejun Heo rc = ahci_stop_engine(ap); 1210d2e75dffSTejun Heo if (rc) 1211d2e75dffSTejun Heo goto out_restart; 1212d2e75dffSTejun Heo 1213d2e75dffSTejun Heo /* need to do CLO? */ 1214d2e75dffSTejun Heo if (!busy) { 1215d2e75dffSTejun Heo rc = 0; 1216d2e75dffSTejun Heo goto out_restart; 1217d2e75dffSTejun Heo } 1218d2e75dffSTejun Heo 1219d2e75dffSTejun Heo if (!(hpriv->cap & HOST_CAP_CLO)) { 1220d2e75dffSTejun Heo rc = -EOPNOTSUPP; 1221d2e75dffSTejun Heo goto out_restart; 1222d2e75dffSTejun Heo } 1223d2e75dffSTejun Heo 1224d2e75dffSTejun Heo /* perform CLO */ 1225c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 1226c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 1227c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 1228c6fd2807SJeff Garzik 1229d2e75dffSTejun Heo rc = 0; 1230c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 1231c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 1232c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 1233d2e75dffSTejun Heo rc = -EIO; 1234c6fd2807SJeff Garzik 1235d2e75dffSTejun Heo /* restart engine */ 1236d2e75dffSTejun Heo out_restart: 1237d2e75dffSTejun Heo ahci_start_engine(ap); 1238d2e75dffSTejun Heo return rc; 1239c6fd2807SJeff Garzik } 1240c6fd2807SJeff Garzik 124191c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, 124291c4a2e0STejun Heo struct ata_taskfile *tf, int is_cmd, u16 flags, 124391c4a2e0STejun Heo unsigned long timeout_msec) 124491c4a2e0STejun Heo { 124591c4a2e0STejun Heo const u32 cmd_fis_len = 5; /* five dwords */ 124691c4a2e0STejun Heo struct ahci_port_priv *pp = ap->private_data; 124791c4a2e0STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 124891c4a2e0STejun Heo u8 *fis = pp->cmd_tbl; 124991c4a2e0STejun Heo u32 tmp; 125091c4a2e0STejun Heo 125191c4a2e0STejun Heo /* prep the command */ 125291c4a2e0STejun Heo ata_tf_to_fis(tf, pmp, is_cmd, fis); 125391c4a2e0STejun Heo ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); 125491c4a2e0STejun Heo 125591c4a2e0STejun Heo /* issue & wait */ 125691c4a2e0STejun Heo writel(1, port_mmio + PORT_CMD_ISSUE); 125791c4a2e0STejun Heo 125891c4a2e0STejun Heo if (timeout_msec) { 125991c4a2e0STejun Heo tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 126091c4a2e0STejun Heo 1, timeout_msec); 126191c4a2e0STejun Heo if (tmp & 0x1) { 126291c4a2e0STejun Heo ahci_kick_engine(ap, 1); 126391c4a2e0STejun Heo return -EBUSY; 126491c4a2e0STejun Heo } 126591c4a2e0STejun Heo } else 126691c4a2e0STejun Heo readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 126791c4a2e0STejun Heo 126891c4a2e0STejun Heo return 0; 126991c4a2e0STejun Heo } 127091c4a2e0STejun Heo 1271cc0680a5STejun Heo static int ahci_do_softreset(struct ata_link *link, unsigned int *class, 1272a9cf5e85STejun Heo int pmp, unsigned long deadline) 1273c6fd2807SJeff Garzik { 1274cc0680a5STejun Heo struct ata_port *ap = link->ap; 1275c6fd2807SJeff Garzik const char *reason = NULL; 12762cbb79ebSTejun Heo unsigned long now, msecs; 1277c6fd2807SJeff Garzik struct ata_taskfile tf; 1278c6fd2807SJeff Garzik int rc; 1279c6fd2807SJeff Garzik 1280c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1281c6fd2807SJeff Garzik 1282cc0680a5STejun Heo if (ata_link_offline(link)) { 1283c6fd2807SJeff Garzik DPRINTK("PHY reports no device\n"); 1284c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 1285c6fd2807SJeff Garzik return 0; 1286c6fd2807SJeff Garzik } 1287c6fd2807SJeff Garzik 1288c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 1289d2e75dffSTejun Heo rc = ahci_kick_engine(ap, 1); 1290994056d7STejun Heo if (rc && rc != -EOPNOTSUPP) 1291cc0680a5STejun Heo ata_link_printk(link, KERN_WARNING, 1292994056d7STejun Heo "failed to reset engine (errno=%d)\n", rc); 1293c6fd2807SJeff Garzik 1294cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1295c6fd2807SJeff Garzik 1296c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 12972cbb79ebSTejun Heo msecs = 0; 12982cbb79ebSTejun Heo now = jiffies; 12992cbb79ebSTejun Heo if (time_after(now, deadline)) 13002cbb79ebSTejun Heo msecs = jiffies_to_msecs(deadline - now); 13012cbb79ebSTejun Heo 1302c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 1303a9cf5e85STejun Heo if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, 130491c4a2e0STejun Heo AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { 1305c6fd2807SJeff Garzik rc = -EIO; 1306c6fd2807SJeff Garzik reason = "1st FIS failed"; 1307c6fd2807SJeff Garzik goto fail; 1308c6fd2807SJeff Garzik } 1309c6fd2807SJeff Garzik 1310c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 1311c6fd2807SJeff Garzik msleep(1); 1312c6fd2807SJeff Garzik 1313c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 1314c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 1315a9cf5e85STejun Heo ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1316c6fd2807SJeff Garzik 131788ff6eafSTejun Heo /* wait a while before checking status */ 131888ff6eafSTejun Heo ata_wait_after_reset(ap, deadline); 1319c6fd2807SJeff Garzik 1320d4b2bab4STejun Heo rc = ata_wait_ready(ap, deadline); 13219b89391cSTejun Heo /* link occupied, -ENODEV too is an error */ 13229b89391cSTejun Heo if (rc) { 1323c6fd2807SJeff Garzik reason = "device not ready"; 1324c6fd2807SJeff Garzik goto fail; 1325c6fd2807SJeff Garzik } 1326c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1327c6fd2807SJeff Garzik 1328c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 1329c6fd2807SJeff Garzik return 0; 1330c6fd2807SJeff Garzik 1331c6fd2807SJeff Garzik fail: 1332cc0680a5STejun Heo ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); 1333c6fd2807SJeff Garzik return rc; 1334c6fd2807SJeff Garzik } 1335c6fd2807SJeff Garzik 1336cc0680a5STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class, 1337a9cf5e85STejun Heo unsigned long deadline) 1338a9cf5e85STejun Heo { 13397d50b60bSTejun Heo int pmp = 0; 13407d50b60bSTejun Heo 13417d50b60bSTejun Heo if (link->ap->flags & ATA_FLAG_PMP) 13427d50b60bSTejun Heo pmp = SATA_PMP_CTRL_PORT; 13437d50b60bSTejun Heo 13447d50b60bSTejun Heo return ahci_do_softreset(link, class, pmp, deadline); 1345a9cf5e85STejun Heo } 1346a9cf5e85STejun Heo 1347cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1348d4b2bab4STejun Heo unsigned long deadline) 1349c6fd2807SJeff Garzik { 1350cc0680a5STejun Heo struct ata_port *ap = link->ap; 1351c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1352c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1353c6fd2807SJeff Garzik struct ata_taskfile tf; 1354c6fd2807SJeff Garzik int rc; 1355c6fd2807SJeff Garzik 1356c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1357c6fd2807SJeff Garzik 13584447d351STejun Heo ahci_stop_engine(ap); 1359c6fd2807SJeff Garzik 1360c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1361cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1362dfd7a3dbSTejun Heo tf.command = 0x80; 13639977126cSTejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1364c6fd2807SJeff Garzik 1365cc0680a5STejun Heo rc = sata_std_hardreset(link, class, deadline); 1366c6fd2807SJeff Garzik 13674447d351STejun Heo ahci_start_engine(ap); 1368c6fd2807SJeff Garzik 1369cc0680a5STejun Heo if (rc == 0 && ata_link_online(link)) 1370c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 13717d50b60bSTejun Heo if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) 1372c6fd2807SJeff Garzik *class = ATA_DEV_NONE; 1373c6fd2807SJeff Garzik 1374c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1375c6fd2807SJeff Garzik return rc; 1376c6fd2807SJeff Garzik } 1377c6fd2807SJeff Garzik 1378cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 1379d4b2bab4STejun Heo unsigned long deadline) 1380ad616ffbSTejun Heo { 1381cc0680a5STejun Heo struct ata_port *ap = link->ap; 1382da3dbb17STejun Heo u32 serror; 1383ad616ffbSTejun Heo int rc; 1384ad616ffbSTejun Heo 1385ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1386ad616ffbSTejun Heo 13874447d351STejun Heo ahci_stop_engine(ap); 1388ad616ffbSTejun Heo 1389cc0680a5STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 1390d4b2bab4STejun Heo deadline); 1391ad616ffbSTejun Heo 1392ad616ffbSTejun Heo /* vt8251 needs SError cleared for the port to operate */ 1393da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1394da3dbb17STejun Heo ahci_scr_write(ap, SCR_ERROR, serror); 1395ad616ffbSTejun Heo 13964447d351STejun Heo ahci_start_engine(ap); 1397ad616ffbSTejun Heo 1398ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1399ad616ffbSTejun Heo 1400ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1401ad616ffbSTejun Heo * request follow-up softreset. 1402ad616ffbSTejun Heo */ 1403ad616ffbSTejun Heo return rc ?: -EAGAIN; 1404ad616ffbSTejun Heo } 1405ad616ffbSTejun Heo 1406edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 1407edc93052STejun Heo unsigned long deadline) 1408edc93052STejun Heo { 1409edc93052STejun Heo struct ata_port *ap = link->ap; 1410edc93052STejun Heo struct ahci_port_priv *pp = ap->private_data; 1411edc93052STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1412edc93052STejun Heo struct ata_taskfile tf; 1413edc93052STejun Heo int rc; 1414edc93052STejun Heo 1415edc93052STejun Heo ahci_stop_engine(ap); 1416edc93052STejun Heo 1417edc93052STejun Heo /* clear D2H reception area to properly wait for D2H FIS */ 1418edc93052STejun Heo ata_tf_init(link->device, &tf); 1419edc93052STejun Heo tf.command = 0x80; 1420edc93052STejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1421edc93052STejun Heo 1422edc93052STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 1423edc93052STejun Heo deadline); 1424edc93052STejun Heo 1425edc93052STejun Heo ahci_start_engine(ap); 1426edc93052STejun Heo 1427edc93052STejun Heo if (rc || ata_link_offline(link)) 1428edc93052STejun Heo return rc; 1429edc93052STejun Heo 1430edc93052STejun Heo /* spec mandates ">= 2ms" before checking status */ 1431edc93052STejun Heo msleep(150); 1432edc93052STejun Heo 1433edc93052STejun Heo /* The pseudo configuration device on SIMG4726 attached to 1434edc93052STejun Heo * ASUS P5W-DH Deluxe doesn't send signature FIS after 1435edc93052STejun Heo * hardreset if no device is attached to the first downstream 1436edc93052STejun Heo * port && the pseudo device locks up on SRST w/ PMP==0. To 1437edc93052STejun Heo * work around this, wait for !BSY only briefly. If BSY isn't 1438edc93052STejun Heo * cleared, perform CLO and proceed to IDENTIFY (achieved by 1439edc93052STejun Heo * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA). 1440edc93052STejun Heo * 1441edc93052STejun Heo * Wait for two seconds. Devices attached to downstream port 1442edc93052STejun Heo * which can't process the following IDENTIFY after this will 1443edc93052STejun Heo * have to be reset again. For most cases, this should 1444edc93052STejun Heo * suffice while making probing snappish enough. 1445edc93052STejun Heo */ 1446edc93052STejun Heo rc = ata_wait_ready(ap, jiffies + 2 * HZ); 1447edc93052STejun Heo if (rc) 1448edc93052STejun Heo ahci_kick_engine(ap, 0); 1449edc93052STejun Heo 1450edc93052STejun Heo return 0; 1451edc93052STejun Heo } 1452edc93052STejun Heo 1453cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class) 1454c6fd2807SJeff Garzik { 1455cc0680a5STejun Heo struct ata_port *ap = link->ap; 14564447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1457c6fd2807SJeff Garzik u32 new_tmp, tmp; 1458c6fd2807SJeff Garzik 1459cc0680a5STejun Heo ata_std_postreset(link, class); 1460c6fd2807SJeff Garzik 1461c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1462c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1463c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1464c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1465c6fd2807SJeff Garzik else 1466c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1467c6fd2807SJeff Garzik if (new_tmp != tmp) { 1468c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1469c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1470c6fd2807SJeff Garzik } 1471c6fd2807SJeff Garzik } 1472c6fd2807SJeff Garzik 14737d50b60bSTejun Heo static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, 14747d50b60bSTejun Heo unsigned long deadline) 14757d50b60bSTejun Heo { 14767d50b60bSTejun Heo return ahci_do_softreset(link, class, link->pmp, deadline); 14777d50b60bSTejun Heo } 14787d50b60bSTejun Heo 1479c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap) 1480c6fd2807SJeff Garzik { 14810d5ff566STejun Heo void __iomem *mmio = ap->ioaddr.cmd_addr; 1482c6fd2807SJeff Garzik 1483c6fd2807SJeff Garzik return readl(mmio + PORT_TFDATA) & 0xFF; 1484c6fd2807SJeff Garzik } 1485c6fd2807SJeff Garzik 1486c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 1487c6fd2807SJeff Garzik { 1488c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1489c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1490c6fd2807SJeff Garzik 1491c6fd2807SJeff Garzik ata_tf_from_fis(d2h_fis, tf); 1492c6fd2807SJeff Garzik } 1493c6fd2807SJeff Garzik 1494c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1495c6fd2807SJeff Garzik { 1496c6fd2807SJeff Garzik struct scatterlist *sg; 1497ff2aeb1eSTejun Heo struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1498ff2aeb1eSTejun Heo unsigned int si; 1499c6fd2807SJeff Garzik 1500c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1501c6fd2807SJeff Garzik 1502c6fd2807SJeff Garzik /* 1503c6fd2807SJeff Garzik * Next, the S/G list. 1504c6fd2807SJeff Garzik */ 1505ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) { 1506c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1507c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1508c6fd2807SJeff Garzik 1509ff2aeb1eSTejun Heo ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); 1510ff2aeb1eSTejun Heo ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); 1511ff2aeb1eSTejun Heo ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); 1512c6fd2807SJeff Garzik } 1513c6fd2807SJeff Garzik 1514ff2aeb1eSTejun Heo return si; 1515c6fd2807SJeff Garzik } 1516c6fd2807SJeff Garzik 1517c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1518c6fd2807SJeff Garzik { 1519c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1520c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1521405e66b3STejun Heo int is_atapi = ata_is_atapi(qc->tf.protocol); 1522c6fd2807SJeff Garzik void *cmd_tbl; 1523c6fd2807SJeff Garzik u32 opts; 1524c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1525c6fd2807SJeff Garzik unsigned int n_elem; 1526c6fd2807SJeff Garzik 1527c6fd2807SJeff Garzik /* 1528c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1529c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1530c6fd2807SJeff Garzik */ 1531c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1532c6fd2807SJeff Garzik 15337d50b60bSTejun Heo ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); 1534c6fd2807SJeff Garzik if (is_atapi) { 1535c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1536c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1537c6fd2807SJeff Garzik } 1538c6fd2807SJeff Garzik 1539c6fd2807SJeff Garzik n_elem = 0; 1540c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1541c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1542c6fd2807SJeff Garzik 1543c6fd2807SJeff Garzik /* 1544c6fd2807SJeff Garzik * Fill in command slot information. 1545c6fd2807SJeff Garzik */ 15467d50b60bSTejun Heo opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); 1547c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1548c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1549c6fd2807SJeff Garzik if (is_atapi) 1550c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1551c6fd2807SJeff Garzik 1552c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1553c6fd2807SJeff Garzik } 1554c6fd2807SJeff Garzik 1555c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1556c6fd2807SJeff Garzik { 1557417a1a6dSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1558c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 15597d50b60bSTejun Heo struct ata_eh_info *host_ehi = &ap->link.eh_info; 15607d50b60bSTejun Heo struct ata_link *link = NULL; 15617d50b60bSTejun Heo struct ata_queued_cmd *active_qc; 15627d50b60bSTejun Heo struct ata_eh_info *active_ehi; 1563c6fd2807SJeff Garzik u32 serror; 1564c6fd2807SJeff Garzik 15657d50b60bSTejun Heo /* determine active link */ 15667d50b60bSTejun Heo ata_port_for_each_link(link, ap) 15677d50b60bSTejun Heo if (ata_link_active(link)) 15687d50b60bSTejun Heo break; 15697d50b60bSTejun Heo if (!link) 15707d50b60bSTejun Heo link = &ap->link; 15717d50b60bSTejun Heo 15727d50b60bSTejun Heo active_qc = ata_qc_from_tag(ap, link->active_tag); 15737d50b60bSTejun Heo active_ehi = &link->eh_info; 15747d50b60bSTejun Heo 15757d50b60bSTejun Heo /* record irq stat */ 15767d50b60bSTejun Heo ata_ehi_clear_desc(host_ehi); 15777d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); 1578c6fd2807SJeff Garzik 1579c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1580da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1581c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 15827d50b60bSTejun Heo host_ehi->serror |= serror; 1583c6fd2807SJeff Garzik 158441669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 1585417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) 158641669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 158741669553STejun Heo 158855a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 15897d50b60bSTejun Heo /* If qc is active, charge it; otherwise, the active 15907d50b60bSTejun Heo * link. There's no active qc on NCQ errors. It will 15917d50b60bSTejun Heo * be determined by EH by reading log page 10h. 15927d50b60bSTejun Heo */ 15937d50b60bSTejun Heo if (active_qc) 15947d50b60bSTejun Heo active_qc->err_mask |= AC_ERR_DEV; 15957d50b60bSTejun Heo else 15967d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_DEV; 15977d50b60bSTejun Heo 1598417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) 15997d50b60bSTejun Heo host_ehi->serror &= ~SERR_INTERNAL; 1600c6fd2807SJeff Garzik } 1601c6fd2807SJeff Garzik 1602c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1603c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1604c6fd2807SJeff Garzik 16057d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 16067d50b60bSTejun Heo active_ehi->action |= ATA_EH_SOFTRESET; 16077d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, 16087d50b60bSTejun Heo "unknown FIS %08x %08x %08x %08x" , 1609c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1610c6fd2807SJeff Garzik } 1611c6fd2807SJeff Garzik 16127d50b60bSTejun Heo if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { 16137d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 16147d50b60bSTejun Heo active_ehi->action |= ATA_EH_SOFTRESET; 16157d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, "incorrect PMP"); 16167d50b60bSTejun Heo } 1617c6fd2807SJeff Garzik 16187d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 16197d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_HOST_BUS; 16207d50b60bSTejun Heo host_ehi->action |= ATA_EH_SOFTRESET; 16217d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "host bus error"); 16227d50b60bSTejun Heo } 16237d50b60bSTejun Heo 16247d50b60bSTejun Heo if (irq_stat & PORT_IRQ_IF_ERR) { 16257d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_ATA_BUS; 16267d50b60bSTejun Heo host_ehi->action |= ATA_EH_SOFTRESET; 16277d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "interface fatal error"); 16287d50b60bSTejun Heo } 16297d50b60bSTejun Heo 16307d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 16317d50b60bSTejun Heo ata_ehi_hotplugged(host_ehi); 16327d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "%s", 16337d50b60bSTejun Heo irq_stat & PORT_IRQ_CONNECT ? 16347d50b60bSTejun Heo "connection status changed" : "PHY RDY changed"); 16357d50b60bSTejun Heo } 16367d50b60bSTejun Heo 16377d50b60bSTejun Heo /* okay, let's hand over to EH */ 1638c6fd2807SJeff Garzik 1639c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1640c6fd2807SJeff Garzik ata_port_freeze(ap); 1641c6fd2807SJeff Garzik else 1642c6fd2807SJeff Garzik ata_port_abort(ap); 1643c6fd2807SJeff Garzik } 1644c6fd2807SJeff Garzik 1645df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap) 1646c6fd2807SJeff Garzik { 16474447d351STejun Heo void __iomem *port_mmio = ap->ioaddr.cmd_addr; 16489af5c9c9STejun Heo struct ata_eh_info *ehi = &ap->link.eh_info; 16490291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 16505f226c6bSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1651b06ce3e5STejun Heo int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 1652c6fd2807SJeff Garzik u32 status, qc_active; 1653459ad688STejun Heo int rc; 1654c6fd2807SJeff Garzik 1655c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1656c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1657c6fd2807SJeff Garzik 1658b06ce3e5STejun Heo /* ignore BAD_PMP while resetting */ 1659b06ce3e5STejun Heo if (unlikely(resetting)) 1660b06ce3e5STejun Heo status &= ~PORT_IRQ_BAD_PMP; 1661b06ce3e5STejun Heo 166231556594SKristen Carlson Accardi /* If we are getting PhyRdy, this is 166331556594SKristen Carlson Accardi * just a power state change, we should 166431556594SKristen Carlson Accardi * clear out this, plus the PhyRdy/Comm 166531556594SKristen Carlson Accardi * Wake bits from Serror 166631556594SKristen Carlson Accardi */ 166731556594SKristen Carlson Accardi if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && 166831556594SKristen Carlson Accardi (status & PORT_IRQ_PHYRDY)) { 166931556594SKristen Carlson Accardi status &= ~PORT_IRQ_PHYRDY; 167031556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 167131556594SKristen Carlson Accardi } 167231556594SKristen Carlson Accardi 1673c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1674c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1675c6fd2807SJeff Garzik return; 1676c6fd2807SJeff Garzik } 1677c6fd2807SJeff Garzik 16782f294968SKristen Carlson Accardi if (status & PORT_IRQ_SDB_FIS) { 16795f226c6bSTejun Heo /* If SNotification is available, leave notification 16805f226c6bSTejun Heo * handling to sata_async_notification(). If not, 16815f226c6bSTejun Heo * emulate it by snooping SDB FIS RX area. 16825f226c6bSTejun Heo * 16835f226c6bSTejun Heo * Snooping FIS RX area is probably cheaper than 16845f226c6bSTejun Heo * poking SNotification but some constrollers which 16855f226c6bSTejun Heo * implement SNotification, ICH9 for example, don't 16865f226c6bSTejun Heo * store AN SDB FIS into receive area. 16875f226c6bSTejun Heo */ 16885f226c6bSTejun Heo if (hpriv->cap & HOST_CAP_SNTF) 16895f226c6bSTejun Heo sata_async_notification(ap); 16905f226c6bSTejun Heo else { 16915f226c6bSTejun Heo /* If the 'N' bit in word 0 of the FIS is set, 16925f226c6bSTejun Heo * we just received asynchronous notification. 16935f226c6bSTejun Heo * Tell libata about it. 16942f294968SKristen Carlson Accardi */ 16952f294968SKristen Carlson Accardi const __le32 *f = pp->rx_fis + RX_FIS_SDB; 16962f294968SKristen Carlson Accardi u32 f0 = le32_to_cpu(f[0]); 16972f294968SKristen Carlson Accardi 16987d77b247STejun Heo if (f0 & (1 << 15)) 16997d77b247STejun Heo sata_async_notification(ap); 17002f294968SKristen Carlson Accardi } 17015f226c6bSTejun Heo } 17022f294968SKristen Carlson Accardi 17037d50b60bSTejun Heo /* pp->active_link is valid iff any command is in flight */ 17047d50b60bSTejun Heo if (ap->qc_active && pp->active_link->sactive) 1705c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1706c6fd2807SJeff Garzik else 1707c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1708c6fd2807SJeff Garzik 1709c6fd2807SJeff Garzik rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1710b06ce3e5STejun Heo 1711459ad688STejun Heo /* while resetting, invalid completions are expected */ 1712459ad688STejun Heo if (unlikely(rc < 0 && !resetting)) { 1713c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1714c6fd2807SJeff Garzik ehi->action |= ATA_EH_SOFTRESET; 1715c6fd2807SJeff Garzik ata_port_freeze(ap); 1716c6fd2807SJeff Garzik } 1717c6fd2807SJeff Garzik } 1718c6fd2807SJeff Garzik 1719c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap) 1720c6fd2807SJeff Garzik { 1721c6fd2807SJeff Garzik /* TODO */ 1722c6fd2807SJeff Garzik } 1723c6fd2807SJeff Garzik 17247d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1725c6fd2807SJeff Garzik { 1726cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1727c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1728c6fd2807SJeff Garzik unsigned int i, handled = 0; 1729c6fd2807SJeff Garzik void __iomem *mmio; 1730c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1731c6fd2807SJeff Garzik 1732c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1733c6fd2807SJeff Garzik 1734cca3974eSJeff Garzik hpriv = host->private_data; 17350d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 1736c6fd2807SJeff Garzik 1737c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1738c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1739c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1740c6fd2807SJeff Garzik if (!irq_stat) 1741c6fd2807SJeff Garzik return IRQ_NONE; 1742c6fd2807SJeff Garzik 1743cca3974eSJeff Garzik spin_lock(&host->lock); 1744c6fd2807SJeff Garzik 1745cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1746c6fd2807SJeff Garzik struct ata_port *ap; 1747c6fd2807SJeff Garzik 1748c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1749c6fd2807SJeff Garzik continue; 1750c6fd2807SJeff Garzik 1751cca3974eSJeff Garzik ap = host->ports[i]; 1752c6fd2807SJeff Garzik if (ap) { 1753df69c9c5SJeff Garzik ahci_port_intr(ap); 1754c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1755c6fd2807SJeff Garzik } else { 1756c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1757c6fd2807SJeff Garzik if (ata_ratelimit()) 1758cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1759c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1760c6fd2807SJeff Garzik } 1761c6fd2807SJeff Garzik 1762c6fd2807SJeff Garzik irq_ack |= (1 << i); 1763c6fd2807SJeff Garzik } 1764c6fd2807SJeff Garzik 1765c6fd2807SJeff Garzik if (irq_ack) { 1766c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1767c6fd2807SJeff Garzik handled = 1; 1768c6fd2807SJeff Garzik } 1769c6fd2807SJeff Garzik 1770cca3974eSJeff Garzik spin_unlock(&host->lock); 1771c6fd2807SJeff Garzik 1772c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1773c6fd2807SJeff Garzik 1774c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1775c6fd2807SJeff Garzik } 1776c6fd2807SJeff Garzik 1777c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1778c6fd2807SJeff Garzik { 1779c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 17804447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 17817d50b60bSTejun Heo struct ahci_port_priv *pp = ap->private_data; 17827d50b60bSTejun Heo 17837d50b60bSTejun Heo /* Keep track of the currently active link. It will be used 17847d50b60bSTejun Heo * in completion path to determine whether NCQ phase is in 17857d50b60bSTejun Heo * progress. 17867d50b60bSTejun Heo */ 17877d50b60bSTejun Heo pp->active_link = qc->dev->link; 1788c6fd2807SJeff Garzik 1789c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1790c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1791c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1792c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1793c6fd2807SJeff Garzik 1794c6fd2807SJeff Garzik return 0; 1795c6fd2807SJeff Garzik } 1796c6fd2807SJeff Garzik 1797c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1798c6fd2807SJeff Garzik { 17994447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1800c6fd2807SJeff Garzik 1801c6fd2807SJeff Garzik /* turn IRQ off */ 1802c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1803c6fd2807SJeff Garzik } 1804c6fd2807SJeff Garzik 1805c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1806c6fd2807SJeff Garzik { 18070d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 18084447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1809c6fd2807SJeff Garzik u32 tmp; 1810a7384925SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1811c6fd2807SJeff Garzik 1812c6fd2807SJeff Garzik /* clear IRQ */ 1813c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1814c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1815a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1816c6fd2807SJeff Garzik 18171c954a4dSTejun Heo /* turn IRQ back on */ 18181c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 1819c6fd2807SJeff Garzik } 1820c6fd2807SJeff Garzik 1821c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1822c6fd2807SJeff Garzik { 1823c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1824c6fd2807SJeff Garzik /* restart engine */ 18254447d351STejun Heo ahci_stop_engine(ap); 18264447d351STejun Heo ahci_start_engine(ap); 1827c6fd2807SJeff Garzik } 1828c6fd2807SJeff Garzik 1829c6fd2807SJeff Garzik /* perform recovery */ 18307d50b60bSTejun Heo sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, 18317d50b60bSTejun Heo ahci_hardreset, ahci_postreset, 18327d50b60bSTejun Heo sata_pmp_std_prereset, ahci_pmp_softreset, 18337d50b60bSTejun Heo sata_pmp_std_hardreset, sata_pmp_std_postreset); 1834c6fd2807SJeff Garzik } 1835c6fd2807SJeff Garzik 1836ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap) 1837ad616ffbSTejun Heo { 1838ad616ffbSTejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1839ad616ffbSTejun Heo /* restart engine */ 18404447d351STejun Heo ahci_stop_engine(ap); 18414447d351STejun Heo ahci_start_engine(ap); 1842ad616ffbSTejun Heo } 1843ad616ffbSTejun Heo 1844ad616ffbSTejun Heo /* perform recovery */ 1845ad616ffbSTejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, 1846ad616ffbSTejun Heo ahci_postreset); 1847ad616ffbSTejun Heo } 1848ad616ffbSTejun Heo 1849edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap) 1850edc93052STejun Heo { 1851edc93052STejun Heo if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1852edc93052STejun Heo /* restart engine */ 1853edc93052STejun Heo ahci_stop_engine(ap); 1854edc93052STejun Heo ahci_start_engine(ap); 1855edc93052STejun Heo } 1856edc93052STejun Heo 1857edc93052STejun Heo /* perform recovery */ 1858edc93052STejun Heo ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset, 1859edc93052STejun Heo ahci_postreset); 1860edc93052STejun Heo } 1861edc93052STejun Heo 1862c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1863c6fd2807SJeff Garzik { 1864c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1865c6fd2807SJeff Garzik 1866c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1867d2e75dffSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) 1868d2e75dffSTejun Heo ahci_kick_engine(ap, 1); 1869c6fd2807SJeff Garzik } 1870c6fd2807SJeff Garzik 18717d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap) 18727d50b60bSTejun Heo { 18737d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 18741c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 18757d50b60bSTejun Heo u32 cmd; 18767d50b60bSTejun Heo 18777d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 18787d50b60bSTejun Heo cmd |= PORT_CMD_PMP; 18797d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 18801c954a4dSTejun Heo 18811c954a4dSTejun Heo pp->intr_mask |= PORT_IRQ_BAD_PMP; 18821c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 18837d50b60bSTejun Heo } 18847d50b60bSTejun Heo 18857d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap) 18867d50b60bSTejun Heo { 18877d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 18881c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 18897d50b60bSTejun Heo u32 cmd; 18907d50b60bSTejun Heo 18917d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 18927d50b60bSTejun Heo cmd &= ~PORT_CMD_PMP; 18937d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 18941c954a4dSTejun Heo 18951c954a4dSTejun Heo pp->intr_mask &= ~PORT_IRQ_BAD_PMP; 18961c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 18977d50b60bSTejun Heo } 18987d50b60bSTejun Heo 1899028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap) 1900028a2596SAlexey Dobriyan { 1901028a2596SAlexey Dobriyan ahci_power_up(ap); 1902028a2596SAlexey Dobriyan ahci_start_port(ap); 1903028a2596SAlexey Dobriyan 19047d50b60bSTejun Heo if (ap->nr_pmp_links) 19057d50b60bSTejun Heo ahci_pmp_attach(ap); 19067d50b60bSTejun Heo else 19077d50b60bSTejun Heo ahci_pmp_detach(ap); 19087d50b60bSTejun Heo 1909028a2596SAlexey Dobriyan return 0; 1910028a2596SAlexey Dobriyan } 1911028a2596SAlexey Dobriyan 1912438ac6d5STejun Heo #ifdef CONFIG_PM 1913c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1914c6fd2807SJeff Garzik { 1915c6fd2807SJeff Garzik const char *emsg = NULL; 1916c6fd2807SJeff Garzik int rc; 1917c6fd2807SJeff Garzik 19184447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 19198e16f941STejun Heo if (rc == 0) 19204447d351STejun Heo ahci_power_down(ap); 19218e16f941STejun Heo else { 1922c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1923df69c9c5SJeff Garzik ahci_start_port(ap); 1924c6fd2807SJeff Garzik } 1925c6fd2807SJeff Garzik 1926c6fd2807SJeff Garzik return rc; 1927c6fd2807SJeff Garzik } 1928c6fd2807SJeff Garzik 1929c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1930c6fd2807SJeff Garzik { 1931cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 19320d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1933c6fd2807SJeff Garzik u32 ctl; 1934c6fd2807SJeff Garzik 1935c6fd2807SJeff Garzik if (mesg.event == PM_EVENT_SUSPEND) { 1936c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1937c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1938c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1939c6fd2807SJeff Garzik */ 1940c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1941c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1942c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1943c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1944c6fd2807SJeff Garzik } 1945c6fd2807SJeff Garzik 1946c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1947c6fd2807SJeff Garzik } 1948c6fd2807SJeff Garzik 1949c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1950c6fd2807SJeff Garzik { 1951cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1952c6fd2807SJeff Garzik int rc; 1953c6fd2807SJeff Garzik 1954553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 1955553c4aa6STejun Heo if (rc) 1956553c4aa6STejun Heo return rc; 1957c6fd2807SJeff Garzik 1958c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 19594447d351STejun Heo rc = ahci_reset_controller(host); 1960c6fd2807SJeff Garzik if (rc) 1961c6fd2807SJeff Garzik return rc; 1962c6fd2807SJeff Garzik 19634447d351STejun Heo ahci_init_controller(host); 1964c6fd2807SJeff Garzik } 1965c6fd2807SJeff Garzik 1966cca3974eSJeff Garzik ata_host_resume(host); 1967c6fd2807SJeff Garzik 1968c6fd2807SJeff Garzik return 0; 1969c6fd2807SJeff Garzik } 1970438ac6d5STejun Heo #endif 1971c6fd2807SJeff Garzik 1972c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1973c6fd2807SJeff Garzik { 1974cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1975c6fd2807SJeff Garzik struct ahci_port_priv *pp; 1976c6fd2807SJeff Garzik void *mem; 1977c6fd2807SJeff Garzik dma_addr_t mem_dma; 1978c6fd2807SJeff Garzik int rc; 1979c6fd2807SJeff Garzik 198024dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 1981c6fd2807SJeff Garzik if (!pp) 1982c6fd2807SJeff Garzik return -ENOMEM; 1983c6fd2807SJeff Garzik 1984c6fd2807SJeff Garzik rc = ata_pad_alloc(ap, dev); 198524dc5f33STejun Heo if (rc) 1986c6fd2807SJeff Garzik return rc; 1987c6fd2807SJeff Garzik 198824dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 198924dc5f33STejun Heo GFP_KERNEL); 199024dc5f33STejun Heo if (!mem) 1991c6fd2807SJeff Garzik return -ENOMEM; 1992c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1993c6fd2807SJeff Garzik 1994c6fd2807SJeff Garzik /* 1995c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1996c6fd2807SJeff Garzik * 32 bytes each in size 1997c6fd2807SJeff Garzik */ 1998c6fd2807SJeff Garzik pp->cmd_slot = mem; 1999c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 2000c6fd2807SJeff Garzik 2001c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 2002c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 2003c6fd2807SJeff Garzik 2004c6fd2807SJeff Garzik /* 2005c6fd2807SJeff Garzik * Second item: Received-FIS area 2006c6fd2807SJeff Garzik */ 2007c6fd2807SJeff Garzik pp->rx_fis = mem; 2008c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 2009c6fd2807SJeff Garzik 2010c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 2011c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 2012c6fd2807SJeff Garzik 2013c6fd2807SJeff Garzik /* 2014c6fd2807SJeff Garzik * Third item: data area for storing a single command 2015c6fd2807SJeff Garzik * and its scatter-gather table 2016c6fd2807SJeff Garzik */ 2017c6fd2807SJeff Garzik pp->cmd_tbl = mem; 2018c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 2019c6fd2807SJeff Garzik 2020a7384925SKristen Carlson Accardi /* 2021a7384925SKristen Carlson Accardi * Save off initial list of interrupts to be enabled. 2022a7384925SKristen Carlson Accardi * This could be changed later 2023a7384925SKristen Carlson Accardi */ 2024a7384925SKristen Carlson Accardi pp->intr_mask = DEF_PORT_IRQ; 2025a7384925SKristen Carlson Accardi 2026c6fd2807SJeff Garzik ap->private_data = pp; 2027c6fd2807SJeff Garzik 2028df69c9c5SJeff Garzik /* engage engines, captain */ 2029df69c9c5SJeff Garzik return ahci_port_resume(ap); 2030c6fd2807SJeff Garzik } 2031c6fd2807SJeff Garzik 2032c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 2033c6fd2807SJeff Garzik { 2034c6fd2807SJeff Garzik const char *emsg = NULL; 2035c6fd2807SJeff Garzik int rc; 2036c6fd2807SJeff Garzik 2037c6fd2807SJeff Garzik /* de-initialize port */ 20384447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 2039c6fd2807SJeff Garzik if (rc) 2040c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 2041c6fd2807SJeff Garzik } 2042c6fd2807SJeff Garzik 20434447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 2044c6fd2807SJeff Garzik { 2045c6fd2807SJeff Garzik int rc; 2046c6fd2807SJeff Garzik 2047c6fd2807SJeff Garzik if (using_dac && 2048c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 2049c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 2050c6fd2807SJeff Garzik if (rc) { 2051c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2052c6fd2807SJeff Garzik if (rc) { 2053c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2054c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 2055c6fd2807SJeff Garzik return rc; 2056c6fd2807SJeff Garzik } 2057c6fd2807SJeff Garzik } 2058c6fd2807SJeff Garzik } else { 2059c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 2060c6fd2807SJeff Garzik if (rc) { 2061c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2062c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 2063c6fd2807SJeff Garzik return rc; 2064c6fd2807SJeff Garzik } 2065c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2066c6fd2807SJeff Garzik if (rc) { 2067c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2068c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 2069c6fd2807SJeff Garzik return rc; 2070c6fd2807SJeff Garzik } 2071c6fd2807SJeff Garzik } 2072c6fd2807SJeff Garzik return 0; 2073c6fd2807SJeff Garzik } 2074c6fd2807SJeff Garzik 20754447d351STejun Heo static void ahci_print_info(struct ata_host *host) 2076c6fd2807SJeff Garzik { 20774447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 20784447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 20794447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2080c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 2081c6fd2807SJeff Garzik const char *speed_s; 2082c6fd2807SJeff Garzik u16 cc; 2083c6fd2807SJeff Garzik const char *scc_s; 2084c6fd2807SJeff Garzik 2085c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 2086c6fd2807SJeff Garzik cap = hpriv->cap; 2087c6fd2807SJeff Garzik impl = hpriv->port_map; 2088c6fd2807SJeff Garzik 2089c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 2090c6fd2807SJeff Garzik if (speed == 1) 2091c6fd2807SJeff Garzik speed_s = "1.5"; 2092c6fd2807SJeff Garzik else if (speed == 2) 2093c6fd2807SJeff Garzik speed_s = "3"; 2094c6fd2807SJeff Garzik else 2095c6fd2807SJeff Garzik speed_s = "?"; 2096c6fd2807SJeff Garzik 2097c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 2098c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 2099c6fd2807SJeff Garzik scc_s = "IDE"; 2100c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 2101c6fd2807SJeff Garzik scc_s = "SATA"; 2102c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 2103c6fd2807SJeff Garzik scc_s = "RAID"; 2104c6fd2807SJeff Garzik else 2105c6fd2807SJeff Garzik scc_s = "unknown"; 2106c6fd2807SJeff Garzik 2107c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2108c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 2109c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 2110c6fd2807SJeff Garzik , 2111c6fd2807SJeff Garzik 2112c6fd2807SJeff Garzik (vers >> 24) & 0xff, 2113c6fd2807SJeff Garzik (vers >> 16) & 0xff, 2114c6fd2807SJeff Garzik (vers >> 8) & 0xff, 2115c6fd2807SJeff Garzik vers & 0xff, 2116c6fd2807SJeff Garzik 2117c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 2118c6fd2807SJeff Garzik (cap & 0x1f) + 1, 2119c6fd2807SJeff Garzik speed_s, 2120c6fd2807SJeff Garzik impl, 2121c6fd2807SJeff Garzik scc_s); 2122c6fd2807SJeff Garzik 2123c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2124c6fd2807SJeff Garzik "flags: " 2125203ef6c4STejun Heo "%s%s%s%s%s%s%s" 2126c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 2127c6fd2807SJeff Garzik , 2128c6fd2807SJeff Garzik 2129c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 2130c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 2131203ef6c4STejun Heo cap & (1 << 29) ? "sntf " : "", 2132c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 2133c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 2134c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 2135c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 2136c6fd2807SJeff Garzik 2137c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 2138c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 2139c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 2140c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 2141c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 2142c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 2143c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 2144c6fd2807SJeff Garzik ); 2145c6fd2807SJeff Garzik } 2146c6fd2807SJeff Garzik 2147edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is 2148edc93052STejun Heo * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't 2149edc93052STejun Heo * support PMP and the 4726 either directly exports the device 2150edc93052STejun Heo * attached to the first downstream port or acts as a hardware storage 2151edc93052STejun Heo * controller and emulate a single ATA device (can be RAID 0/1 or some 2152edc93052STejun Heo * other configuration). 2153edc93052STejun Heo * 2154edc93052STejun Heo * When there's no device attached to the first downstream port of the 2155edc93052STejun Heo * 4726, "Config Disk" appears, which is a pseudo ATA device to 2156edc93052STejun Heo * configure the 4726. However, ATA emulation of the device is very 2157edc93052STejun Heo * lame. It doesn't send signature D2H Reg FIS after the initial 2158edc93052STejun Heo * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. 2159edc93052STejun Heo * 2160edc93052STejun Heo * The following function works around the problem by always using 2161edc93052STejun Heo * hardreset on the port and not depending on receiving signature FIS 2162edc93052STejun Heo * afterward. If signature FIS isn't received soon, ATA class is 2163edc93052STejun Heo * assumed without follow-up softreset. 2164edc93052STejun Heo */ 2165edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host) 2166edc93052STejun Heo { 2167edc93052STejun Heo static struct dmi_system_id sysids[] = { 2168edc93052STejun Heo { 2169edc93052STejun Heo .ident = "P5W DH Deluxe", 2170edc93052STejun Heo .matches = { 2171edc93052STejun Heo DMI_MATCH(DMI_SYS_VENDOR, 2172edc93052STejun Heo "ASUSTEK COMPUTER INC"), 2173edc93052STejun Heo DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), 2174edc93052STejun Heo }, 2175edc93052STejun Heo }, 2176edc93052STejun Heo { } 2177edc93052STejun Heo }; 2178edc93052STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 2179edc93052STejun Heo 2180edc93052STejun Heo if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) && 2181edc93052STejun Heo dmi_check_system(sysids)) { 2182edc93052STejun Heo struct ata_port *ap = host->ports[1]; 2183edc93052STejun Heo 2184edc93052STejun Heo dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " 2185edc93052STejun Heo "Deluxe on-board SIMG4726 workaround\n"); 2186edc93052STejun Heo 2187edc93052STejun Heo ap->ops = &ahci_p5wdh_ops; 2188edc93052STejun Heo ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; 2189edc93052STejun Heo } 2190edc93052STejun Heo } 2191edc93052STejun Heo 2192c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2193c6fd2807SJeff Garzik { 2194c6fd2807SJeff Garzik static int printed_version; 21954447d351STejun Heo struct ata_port_info pi = ahci_port_info[ent->driver_data]; 21964447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 219724dc5f33STejun Heo struct device *dev = &pdev->dev; 2198c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 21994447d351STejun Heo struct ata_host *host; 2200*837f5f8fSTejun Heo int n_ports, i, rc; 2201c6fd2807SJeff Garzik 2202c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2203c6fd2807SJeff Garzik 2204c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 2205c6fd2807SJeff Garzik 2206c6fd2807SJeff Garzik if (!printed_version++) 2207c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 2208c6fd2807SJeff Garzik 22094447d351STejun Heo /* acquire resources */ 221024dc5f33STejun Heo rc = pcim_enable_device(pdev); 2211c6fd2807SJeff Garzik if (rc) 2212c6fd2807SJeff Garzik return rc; 2213c6fd2807SJeff Garzik 22140d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 22150d5ff566STejun Heo if (rc == -EBUSY) 221624dc5f33STejun Heo pcim_pin_device(pdev); 22170d5ff566STejun Heo if (rc) 221824dc5f33STejun Heo return rc; 2219c6fd2807SJeff Garzik 2220c4f7792cSTejun Heo if (pdev->vendor == PCI_VENDOR_ID_INTEL && 2221c4f7792cSTejun Heo (pdev->device == 0x2652 || pdev->device == 0x2653)) { 2222c4f7792cSTejun Heo u8 map; 2223c4f7792cSTejun Heo 2224c4f7792cSTejun Heo /* ICH6s share the same PCI ID for both piix and ahci 2225c4f7792cSTejun Heo * modes. Enabling ahci mode while MAP indicates 2226c4f7792cSTejun Heo * combined mode is a bad idea. Yield to ata_piix. 2227c4f7792cSTejun Heo */ 2228c4f7792cSTejun Heo pci_read_config_byte(pdev, ICH_MAP, &map); 2229c4f7792cSTejun Heo if (map & 0x3) { 2230c4f7792cSTejun Heo dev_printk(KERN_INFO, &pdev->dev, "controller is in " 2231c4f7792cSTejun Heo "combined mode, can't enable AHCI mode\n"); 2232c4f7792cSTejun Heo return -ENODEV; 2233c4f7792cSTejun Heo } 2234c4f7792cSTejun Heo } 2235c4f7792cSTejun Heo 223624dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 223724dc5f33STejun Heo if (!hpriv) 223824dc5f33STejun Heo return -ENOMEM; 2239417a1a6dSTejun Heo hpriv->flags |= (unsigned long)pi.private_data; 2240417a1a6dSTejun Heo 2241417a1a6dSTejun Heo if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) 2242417a1a6dSTejun Heo pci_intx(pdev, 1); 2243c6fd2807SJeff Garzik 22444447d351STejun Heo /* save initial config */ 2245417a1a6dSTejun Heo ahci_save_initial_config(pdev, hpriv); 2246c6fd2807SJeff Garzik 22474447d351STejun Heo /* prepare host */ 2248274c1fdeSTejun Heo if (hpriv->cap & HOST_CAP_NCQ) 22494447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 22504447d351STejun Heo 22517d50b60bSTejun Heo if (hpriv->cap & HOST_CAP_PMP) 22527d50b60bSTejun Heo pi.flags |= ATA_FLAG_PMP; 22537d50b60bSTejun Heo 2254*837f5f8fSTejun Heo /* CAP.NP sometimes indicate the index of the last enabled 2255*837f5f8fSTejun Heo * port, at other times, that of the last possible port, so 2256*837f5f8fSTejun Heo * determining the maximum port number requires looking at 2257*837f5f8fSTejun Heo * both CAP.NP and port_map. 2258*837f5f8fSTejun Heo */ 2259*837f5f8fSTejun Heo n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 2260*837f5f8fSTejun Heo 2261*837f5f8fSTejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 22624447d351STejun Heo if (!host) 22634447d351STejun Heo return -ENOMEM; 22644447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 22654447d351STejun Heo host->private_data = hpriv; 22664447d351STejun Heo 22674447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 22684447d351STejun Heo struct ata_port *ap = host->ports[i]; 22694447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 22704447d351STejun Heo 2271cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); 2272cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, 2273cbcdd875STejun Heo 0x100 + ap->port_no * 0x80, "port"); 2274cbcdd875STejun Heo 227531556594SKristen Carlson Accardi /* set initial link pm policy */ 227631556594SKristen Carlson Accardi ap->pm_policy = NOT_AVAILABLE; 227731556594SKristen Carlson Accardi 2278dab632e8SJeff Garzik /* standard SATA port setup */ 2279203ef6c4STejun Heo if (hpriv->port_map & (1 << i)) 22804447d351STejun Heo ap->ioaddr.cmd_addr = port_mmio; 2281dab632e8SJeff Garzik 2282dab632e8SJeff Garzik /* disabled/not-implemented port */ 2283dab632e8SJeff Garzik else 2284dab632e8SJeff Garzik ap->ops = &ata_dummy_port_ops; 22854447d351STejun Heo } 2286c6fd2807SJeff Garzik 2287edc93052STejun Heo /* apply workaround for ASUS P5W DH Deluxe mainboard */ 2288edc93052STejun Heo ahci_p5wdh_workaround(host); 2289edc93052STejun Heo 2290c6fd2807SJeff Garzik /* initialize adapter */ 22914447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2292c6fd2807SJeff Garzik if (rc) 229324dc5f33STejun Heo return rc; 2294c6fd2807SJeff Garzik 22954447d351STejun Heo rc = ahci_reset_controller(host); 22964447d351STejun Heo if (rc) 22974447d351STejun Heo return rc; 2298c6fd2807SJeff Garzik 22994447d351STejun Heo ahci_init_controller(host); 23004447d351STejun Heo ahci_print_info(host); 2301c6fd2807SJeff Garzik 23024447d351STejun Heo pci_set_master(pdev); 23034447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 23044447d351STejun Heo &ahci_sht); 2305c6fd2807SJeff Garzik } 2306c6fd2807SJeff Garzik 2307c6fd2807SJeff Garzik static int __init ahci_init(void) 2308c6fd2807SJeff Garzik { 2309c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 2310c6fd2807SJeff Garzik } 2311c6fd2807SJeff Garzik 2312c6fd2807SJeff Garzik static void __exit ahci_exit(void) 2313c6fd2807SJeff Garzik { 2314c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 2315c6fd2807SJeff Garzik } 2316c6fd2807SJeff Garzik 2317c6fd2807SJeff Garzik 2318c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 2319c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 2320c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2321c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 2322c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2323c6fd2807SJeff Garzik 2324c6fd2807SJeff Garzik module_init(ahci_init); 2325c6fd2807SJeff Garzik module_exit(ahci_exit); 2326