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 52a22e6444STejun Heo static int ahci_skip_host_reset; 53a22e6444STejun Heo module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444); 54a22e6444STejun Heo MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)"); 55a22e6444STejun Heo 5631556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 5731556594SKristen Carlson Accardi enum link_pm policy); 5831556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap); 59c6fd2807SJeff Garzik 60c6fd2807SJeff Garzik enum { 61c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 62648a88beSTejun Heo AHCI_MAX_PORTS = 32, 63c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 64c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 65c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 66c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 67c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 68c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 69c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 70c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 71c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 72c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 73c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 74c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 75c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 76c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 77c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 78c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 79c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 80c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 81c6fd2807SJeff Garzik 82c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 830291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 84c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 85c6fd2807SJeff Garzik 86c6fd2807SJeff Garzik board_ahci = 0, 877a234affSTejun Heo board_ahci_vt8251 = 1, 887a234affSTejun Heo board_ahci_ign_iferr = 2, 897a234affSTejun Heo board_ahci_sb600 = 3, 907a234affSTejun Heo board_ahci_mv = 4, 91e39fc8c9SShane Huang board_ahci_sb700 = 5, 92*e297d99eSTejun Heo board_ahci_mcp65 = 6, 93c6fd2807SJeff Garzik 94c6fd2807SJeff Garzik /* global controller registers */ 95c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 96c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 97c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 98c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 99c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 100c6fd2807SJeff Garzik 101c6fd2807SJeff Garzik /* HOST_CTL bits */ 102c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 103c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 104c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 105c6fd2807SJeff Garzik 106c6fd2807SJeff Garzik /* HOST_CAP bits */ 107c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 1087d50b60bSTejun Heo HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ 109c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 11031556594SKristen Carlson Accardi HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ 111c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 112203ef6c4STejun Heo HOST_CAP_SNTF = (1 << 29), /* SNotification register */ 113c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 114c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 115c6fd2807SJeff Garzik 116c6fd2807SJeff Garzik /* registers for each SATA port */ 117c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 118c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 119c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 120c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 121c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 122c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 123c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 124c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 125c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 126c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 127c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 128c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 129c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 130c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 131203ef6c4STejun Heo PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ 132c6fd2807SJeff Garzik 133c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 134c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 135c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 136c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 137c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 138c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 139c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 140c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 141c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 142c6fd2807SJeff Garzik 143c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 144c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 145c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 146c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 147c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 148c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 149c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 150c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 151c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 152c6fd2807SJeff Garzik 153c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 154c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 155c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 156c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 1577d50b60bSTejun Heo PORT_IRQ_UNK_FIS | 1587d50b60bSTejun Heo PORT_IRQ_BAD_PMP, 159c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 160c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 161c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 162c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 163c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 164c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 165c6fd2807SJeff Garzik 166c6fd2807SJeff Garzik /* PORT_CMD bits */ 16731556594SKristen Carlson Accardi PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ 16831556594SKristen Carlson Accardi PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ 169c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 1707d50b60bSTejun Heo PORT_CMD_PMP = (1 << 17), /* PMP attached */ 171c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 172c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 173c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 174c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 175c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 176c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 177c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 178c6fd2807SJeff Garzik 179c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 180c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 181c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 182c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 183c6fd2807SJeff Garzik 184417a1a6dSTejun Heo /* hpriv->flags bits */ 185417a1a6dSTejun Heo AHCI_HFLAG_NO_NCQ = (1 << 0), 186417a1a6dSTejun Heo AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ 187417a1a6dSTejun Heo AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ 188417a1a6dSTejun Heo AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ 189417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ 190417a1a6dSTejun Heo AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ 1916949b914STejun Heo AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ 19231556594SKristen Carlson Accardi AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ 193a878539eSJeff Garzik AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ 194*e297d99eSTejun Heo AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ 195417a1a6dSTejun Heo 196c6fd2807SJeff Garzik /* ap->flags bits */ 1971188c0d8STejun Heo 1981188c0d8STejun Heo AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 1991188c0d8STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 20031556594SKristen Carlson Accardi ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | 20131556594SKristen Carlson Accardi ATA_FLAG_IPM, 202c4f7792cSTejun Heo 203c4f7792cSTejun Heo ICH_MAP = 0x90, /* ICH MAP register */ 204c6fd2807SJeff Garzik }; 205c6fd2807SJeff Garzik 206c6fd2807SJeff Garzik struct ahci_cmd_hdr { 2074ca4e439SAl Viro __le32 opts; 2084ca4e439SAl Viro __le32 status; 2094ca4e439SAl Viro __le32 tbl_addr; 2104ca4e439SAl Viro __le32 tbl_addr_hi; 2114ca4e439SAl Viro __le32 reserved[4]; 212c6fd2807SJeff Garzik }; 213c6fd2807SJeff Garzik 214c6fd2807SJeff Garzik struct ahci_sg { 2154ca4e439SAl Viro __le32 addr; 2164ca4e439SAl Viro __le32 addr_hi; 2174ca4e439SAl Viro __le32 reserved; 2184ca4e439SAl Viro __le32 flags_size; 219c6fd2807SJeff Garzik }; 220c6fd2807SJeff Garzik 221c6fd2807SJeff Garzik struct ahci_host_priv { 222417a1a6dSTejun Heo unsigned int flags; /* AHCI_HFLAG_* */ 223d447df14STejun Heo u32 cap; /* cap to use */ 224d447df14STejun Heo u32 port_map; /* port map to use */ 225d447df14STejun Heo u32 saved_cap; /* saved initial cap */ 226d447df14STejun Heo u32 saved_port_map; /* saved initial port_map */ 227c6fd2807SJeff Garzik }; 228c6fd2807SJeff Garzik 229c6fd2807SJeff Garzik struct ahci_port_priv { 2307d50b60bSTejun Heo struct ata_link *active_link; 231c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 232c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 233c6fd2807SJeff Garzik void *cmd_tbl; 234c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 235c6fd2807SJeff Garzik void *rx_fis; 236c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2370291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2380291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2390291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 240afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 241a7384925SKristen Carlson Accardi u32 intr_mask; /* interrupts to enable */ 242c6fd2807SJeff Garzik }; 243c6fd2807SJeff Garzik 244da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); 245da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); 246c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 247c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 2484c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); 249c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 250c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 251c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 252c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 253c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 2547d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap); 2557d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap); 256a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class, 257a1efdabaSTejun Heo unsigned long deadline); 258a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 259a1efdabaSTejun Heo unsigned long deadline); 260a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 261a1efdabaSTejun Heo unsigned long deadline); 262a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 263a1efdabaSTejun Heo unsigned long deadline); 264a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class); 265c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 266c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 267df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 268a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev); 269dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); 270dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 271dab632e8SJeff Garzik u32 opts); 272438ac6d5STejun Heo #ifdef CONFIG_PM 273c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 274c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 275c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 276438ac6d5STejun Heo #endif 277c6fd2807SJeff Garzik 278ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = { 279ee959b00STony Jones &dev_attr_link_power_management_policy, 28031556594SKristen Carlson Accardi NULL 28131556594SKristen Carlson Accardi }; 28231556594SKristen Carlson Accardi 283c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 28468d1d07bSTejun Heo ATA_NCQ_SHT(DRV_NAME), 285c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 286c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 287c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 28831556594SKristen Carlson Accardi .shost_attrs = ahci_shost_attrs, 289c6fd2807SJeff Garzik }; 290c6fd2807SJeff Garzik 291029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = { 292029cfd6bSTejun Heo .inherits = &sata_pmp_port_ops, 293029cfd6bSTejun Heo 2947d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 295c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 296c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 2974c9bf4e7STejun Heo .qc_fill_rtf = ahci_qc_fill_rtf, 298c6fd2807SJeff Garzik 299c6fd2807SJeff Garzik .freeze = ahci_freeze, 300c6fd2807SJeff Garzik .thaw = ahci_thaw, 301a1efdabaSTejun Heo .softreset = ahci_softreset, 302a1efdabaSTejun Heo .hardreset = ahci_hardreset, 303a1efdabaSTejun Heo .postreset = ahci_postreset, 304071f44b1STejun Heo .pmp_softreset = ahci_softreset, 305c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 306c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 307029cfd6bSTejun Heo .dev_config = ahci_dev_config, 308c6fd2807SJeff Garzik 309029cfd6bSTejun Heo .scr_read = ahci_scr_read, 310029cfd6bSTejun Heo .scr_write = ahci_scr_write, 3117d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3127d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3137d50b60bSTejun Heo 314029cfd6bSTejun Heo .enable_pm = ahci_enable_alpm, 315029cfd6bSTejun Heo .disable_pm = ahci_disable_alpm, 316438ac6d5STejun Heo #ifdef CONFIG_PM 317c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 318c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 319438ac6d5STejun Heo #endif 320c6fd2807SJeff Garzik .port_start = ahci_port_start, 321c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 322c6fd2807SJeff Garzik }; 323c6fd2807SJeff Garzik 324029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = { 325029cfd6bSTejun Heo .inherits = &ahci_ops, 326a1efdabaSTejun Heo .hardreset = ahci_vt8251_hardreset, 327ad616ffbSTejun Heo }; 328ad616ffbSTejun Heo 329029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = { 330029cfd6bSTejun Heo .inherits = &ahci_ops, 331a1efdabaSTejun Heo .hardreset = ahci_p5wdh_hardreset, 332edc93052STejun Heo }; 333edc93052STejun Heo 334417a1a6dSTejun Heo #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 335417a1a6dSTejun Heo 336c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 337c6fd2807SJeff Garzik /* board_ahci */ 338c6fd2807SJeff Garzik { 3391188c0d8STejun Heo .flags = AHCI_FLAG_COMMON, 340c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 341469248abSJeff Garzik .udma_mask = ATA_UDMA6, 342c6fd2807SJeff Garzik .port_ops = &ahci_ops, 343c6fd2807SJeff Garzik }, 344c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 345c6fd2807SJeff Garzik { 3466949b914STejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), 347417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 348c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 349469248abSJeff Garzik .udma_mask = ATA_UDMA6, 350ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 351c6fd2807SJeff Garzik }, 35241669553STejun Heo /* board_ahci_ign_iferr */ 35341669553STejun Heo { 354417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), 355417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 35641669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 357469248abSJeff Garzik .udma_mask = ATA_UDMA6, 35841669553STejun Heo .port_ops = &ahci_ops, 35941669553STejun Heo }, 36055a61604SConke Hu /* board_ahci_sb600 */ 36155a61604SConke Hu { 362417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 36322b5e7a7STejun Heo AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | 364a878539eSJeff Garzik AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), 365417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 36655a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 367469248abSJeff Garzik .udma_mask = ATA_UDMA6, 36855a61604SConke Hu .port_ops = &ahci_ops, 36955a61604SConke Hu }, 370cd70c266SJeff Garzik /* board_ahci_mv */ 371cd70c266SJeff Garzik { 372417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | 373417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA), 374cd70c266SJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 375417a1a6dSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 376cd70c266SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 377cd70c266SJeff Garzik .udma_mask = ATA_UDMA6, 378cd70c266SJeff Garzik .port_ops = &ahci_ops, 379cd70c266SJeff Garzik }, 380e39fc8c9SShane Huang /* board_ahci_sb700 */ 381e39fc8c9SShane Huang { 382e39fc8c9SShane Huang AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 383e39fc8c9SShane Huang AHCI_HFLAG_NO_PMP), 384e39fc8c9SShane Huang .flags = AHCI_FLAG_COMMON, 385e39fc8c9SShane Huang .pio_mask = 0x1f, /* pio0-4 */ 386e39fc8c9SShane Huang .udma_mask = ATA_UDMA6, 387e39fc8c9SShane Huang .port_ops = &ahci_ops, 388e39fc8c9SShane Huang }, 389*e297d99eSTejun Heo /* board_ahci_mcp65 */ 390*e297d99eSTejun Heo { 391*e297d99eSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), 392*e297d99eSTejun Heo .flags = AHCI_FLAG_COMMON, 393*e297d99eSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 394*e297d99eSTejun Heo .udma_mask = ATA_UDMA6, 395*e297d99eSTejun Heo .port_ops = &ahci_ops, 396*e297d99eSTejun Heo }, 397c6fd2807SJeff Garzik }; 398c6fd2807SJeff Garzik 399c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 400c6fd2807SJeff Garzik /* Intel */ 40154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 40254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 40354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 40454bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 40554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 40682490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 40754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 40854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 40954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 41054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 4117a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ 4127a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ 4137a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ 4147a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ 4157a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ 4167a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ 4177a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ 4187a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ 4197a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ 4207a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ 4217a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ 4227a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ 4237a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ 4247a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ 4257a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ 4267a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ 4277a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ 428d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ 429d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ 43016ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ 43116ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ 432c6fd2807SJeff Garzik 433e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 434e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 435e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 436c6fd2807SJeff Garzik 437c6fd2807SJeff Garzik /* ATI */ 438c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 439e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */ 440e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */ 441e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */ 442e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */ 443e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ 444e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ 445c6fd2807SJeff Garzik 446c6fd2807SJeff Garzik /* VIA */ 44754bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 448bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 449c6fd2807SJeff Garzik 450c6fd2807SJeff Garzik /* NVIDIA */ 451*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */ 452*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */ 453*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */ 454*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */ 455*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */ 456*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */ 457*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */ 458*e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */ 4596fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 4606fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 4616fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 4626fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 463895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 464895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 465895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 466895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 467895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 468895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 469895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 470895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 4710522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */ 4720522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */ 4730522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */ 4740522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */ 4750522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */ 4760522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */ 4770522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */ 4780522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */ 4790522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */ 4800522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */ 4810522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */ 4820522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */ 4830522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */ 4840522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */ 4850522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */ 4860522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */ 4870522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */ 4880522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */ 4890522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */ 4900522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */ 4910522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */ 4920522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ 4930522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ 4940522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ 4956ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */ 4966ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */ 4976ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */ 4986ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */ 4997100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ 5007100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ 5017100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ 5027100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ 5037100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ 5047100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ 5057100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ 5067100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ 50770d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */ 50870d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */ 50970d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */ 51070d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */ 51170d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */ 51270d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ 51370d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ 51470d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ 5153072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */ 5163072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */ 5173072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */ 5183072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */ 519c6fd2807SJeff Garzik 520c6fd2807SJeff Garzik /* SiS */ 52154bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 52254bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ 52354bb3a94SJeff Garzik { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 524c6fd2807SJeff Garzik 525cd70c266SJeff Garzik /* Marvell */ 526cd70c266SJeff Garzik { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ 527c40e7cb8SJose Alberto Reguero { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ 528cd70c266SJeff Garzik 529415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 530415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 531c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 532415ae2b5SJeff Garzik 533c6fd2807SJeff Garzik { } /* terminate list */ 534c6fd2807SJeff Garzik }; 535c6fd2807SJeff Garzik 536c6fd2807SJeff Garzik 537c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 538c6fd2807SJeff Garzik .name = DRV_NAME, 539c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 540c6fd2807SJeff Garzik .probe = ahci_init_one, 54124dc5f33STejun Heo .remove = ata_pci_remove_one, 542438ac6d5STejun Heo #ifdef CONFIG_PM 543c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 544c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 545438ac6d5STejun Heo #endif 546c6fd2807SJeff Garzik }; 547c6fd2807SJeff Garzik 548c6fd2807SJeff Garzik 54998fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 55098fa4b60STejun Heo { 55198fa4b60STejun Heo return (cap & 0x1f) + 1; 55298fa4b60STejun Heo } 55398fa4b60STejun Heo 554dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host, 555dab632e8SJeff Garzik unsigned int port_no) 556dab632e8SJeff Garzik { 557dab632e8SJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 558dab632e8SJeff Garzik 559dab632e8SJeff Garzik return mmio + 0x100 + (port_no * 0x80); 560dab632e8SJeff Garzik } 561dab632e8SJeff Garzik 5624447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 563c6fd2807SJeff Garzik { 564dab632e8SJeff Garzik return __ahci_port_base(ap->host, ap->port_no); 565c6fd2807SJeff Garzik } 566c6fd2807SJeff Garzik 567b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio) 568b710a1f4STejun Heo { 56915fe982eSTejun Heo int i; 570b710a1f4STejun Heo u32 tmp; 571b710a1f4STejun Heo 572b710a1f4STejun Heo /* turn on AHCI_EN */ 573b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 57415fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 57515fe982eSTejun Heo return; 57615fe982eSTejun Heo 57715fe982eSTejun Heo /* Some controllers need AHCI_EN to be written multiple times. 57815fe982eSTejun Heo * Try a few times before giving up. 57915fe982eSTejun Heo */ 58015fe982eSTejun Heo for (i = 0; i < 5; i++) { 581b710a1f4STejun Heo tmp |= HOST_AHCI_EN; 582b710a1f4STejun Heo writel(tmp, mmio + HOST_CTL); 583b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ 58415fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 58515fe982eSTejun Heo return; 58615fe982eSTejun Heo msleep(10); 587b710a1f4STejun Heo } 58815fe982eSTejun Heo 58915fe982eSTejun Heo WARN_ON(1); 590b710a1f4STejun Heo } 591b710a1f4STejun Heo 592d447df14STejun Heo /** 593d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 5944447d351STejun Heo * @pdev: target PCI device 5954447d351STejun Heo * @hpriv: host private area to store config values 596d447df14STejun Heo * 597d447df14STejun Heo * Some registers containing configuration info might be setup by 598d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 599d447df14STejun Heo * initial values of those registers into @hpriv such that they 600d447df14STejun Heo * can be restored after controller reset. 601d447df14STejun Heo * 602d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 603d447df14STejun Heo * 604d447df14STejun Heo * LOCKING: 605d447df14STejun Heo * None. 606d447df14STejun Heo */ 6074447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 6084447d351STejun Heo struct ahci_host_priv *hpriv) 609d447df14STejun Heo { 6104447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 611d447df14STejun Heo u32 cap, port_map; 61217199b18STejun Heo int i; 613c40e7cb8SJose Alberto Reguero int mv; 614d447df14STejun Heo 615b710a1f4STejun Heo /* make sure AHCI mode is enabled before accessing CAP */ 616b710a1f4STejun Heo ahci_enable_ahci(mmio); 617b710a1f4STejun Heo 618d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 619d447df14STejun Heo * reset. Values without are used for driver operation. 620d447df14STejun Heo */ 621d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 622d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 623d447df14STejun Heo 624274c1fdeSTejun Heo /* some chips have errata preventing 64bit use */ 625417a1a6dSTejun Heo if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { 626c7a42156STejun Heo dev_printk(KERN_INFO, &pdev->dev, 627c7a42156STejun Heo "controller can't do 64bit DMA, forcing 32bit\n"); 628c7a42156STejun Heo cap &= ~HOST_CAP_64; 629c7a42156STejun Heo } 630c7a42156STejun Heo 631417a1a6dSTejun Heo if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { 632274c1fdeSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 633274c1fdeSTejun Heo "controller can't do NCQ, turning off CAP_NCQ\n"); 634274c1fdeSTejun Heo cap &= ~HOST_CAP_NCQ; 635274c1fdeSTejun Heo } 636274c1fdeSTejun Heo 637*e297d99eSTejun Heo if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { 638*e297d99eSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 639*e297d99eSTejun Heo "controller can do NCQ, turning on CAP_NCQ\n"); 640*e297d99eSTejun Heo cap |= HOST_CAP_NCQ; 641*e297d99eSTejun Heo } 642*e297d99eSTejun Heo 643258cd846SRoel Kluin if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { 6446949b914STejun Heo dev_printk(KERN_INFO, &pdev->dev, 6456949b914STejun Heo "controller can't do PMP, turning off CAP_PMP\n"); 6466949b914STejun Heo cap &= ~HOST_CAP_PMP; 6476949b914STejun Heo } 6486949b914STejun Heo 649cd70c266SJeff Garzik /* 650cd70c266SJeff Garzik * Temporary Marvell 6145 hack: PATA port presence 651cd70c266SJeff Garzik * is asserted through the standard AHCI port 652cd70c266SJeff Garzik * presence register, as bit 4 (counting from 0) 653cd70c266SJeff Garzik */ 654417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 655c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 656c40e7cb8SJose Alberto Reguero mv = 0x3; 657c40e7cb8SJose Alberto Reguero else 658c40e7cb8SJose Alberto Reguero mv = 0xf; 659cd70c266SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 660cd70c266SJeff Garzik "MV_AHCI HACK: port_map %x -> %x\n", 661c40e7cb8SJose Alberto Reguero port_map, 662c40e7cb8SJose Alberto Reguero port_map & mv); 663cd70c266SJeff Garzik 664c40e7cb8SJose Alberto Reguero port_map &= mv; 665cd70c266SJeff Garzik } 666cd70c266SJeff Garzik 66717199b18STejun Heo /* cross check port_map and cap.n_ports */ 6687a234affSTejun Heo if (port_map) { 669837f5f8fSTejun Heo int map_ports = 0; 67017199b18STejun Heo 671837f5f8fSTejun Heo for (i = 0; i < AHCI_MAX_PORTS; i++) 672837f5f8fSTejun Heo if (port_map & (1 << i)) 673837f5f8fSTejun Heo map_ports++; 67417199b18STejun Heo 675837f5f8fSTejun Heo /* If PI has more ports than n_ports, whine, clear 676837f5f8fSTejun Heo * port_map and let it be generated from n_ports. 67717199b18STejun Heo */ 678837f5f8fSTejun Heo if (map_ports > ahci_nr_ports(cap)) { 6794447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 680837f5f8fSTejun Heo "implemented port map (0x%x) contains more " 681837f5f8fSTejun Heo "ports than nr_ports (%u), using nr_ports\n", 682837f5f8fSTejun Heo port_map, ahci_nr_ports(cap)); 6837a234affSTejun Heo port_map = 0; 6847a234affSTejun Heo } 6857a234affSTejun Heo } 6867a234affSTejun Heo 68717199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 6887a234affSTejun Heo if (!port_map) { 68917199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 6907a234affSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 6917a234affSTejun Heo "forcing PORTS_IMPL to 0x%x\n", port_map); 6927a234affSTejun Heo 6937a234affSTejun Heo /* write the fixed up value to the PI register */ 6947a234affSTejun Heo hpriv->saved_port_map = port_map; 69517199b18STejun Heo } 69617199b18STejun Heo 697d447df14STejun Heo /* record values to use during operation */ 698d447df14STejun Heo hpriv->cap = cap; 699d447df14STejun Heo hpriv->port_map = port_map; 700d447df14STejun Heo } 701d447df14STejun Heo 702d447df14STejun Heo /** 703d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 7044447d351STejun Heo * @host: target ATA host 705d447df14STejun Heo * 706d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 707d447df14STejun Heo * 708d447df14STejun Heo * LOCKING: 709d447df14STejun Heo * None. 710d447df14STejun Heo */ 7114447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 712d447df14STejun Heo { 7134447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 7144447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 7154447d351STejun Heo 716d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 717d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 718d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 719d447df14STejun Heo } 720d447df14STejun Heo 721203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) 722c6fd2807SJeff Garzik { 723203ef6c4STejun Heo static const int offset[] = { 724203ef6c4STejun Heo [SCR_STATUS] = PORT_SCR_STAT, 725203ef6c4STejun Heo [SCR_CONTROL] = PORT_SCR_CTL, 726203ef6c4STejun Heo [SCR_ERROR] = PORT_SCR_ERR, 727203ef6c4STejun Heo [SCR_ACTIVE] = PORT_SCR_ACT, 728203ef6c4STejun Heo [SCR_NOTIFICATION] = PORT_SCR_NTF, 729203ef6c4STejun Heo }; 730203ef6c4STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 731c6fd2807SJeff Garzik 732203ef6c4STejun Heo if (sc_reg < ARRAY_SIZE(offset) && 733203ef6c4STejun Heo (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) 734203ef6c4STejun Heo return offset[sc_reg]; 735da3dbb17STejun Heo return 0; 736c6fd2807SJeff Garzik } 737c6fd2807SJeff Garzik 738203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 739c6fd2807SJeff Garzik { 740203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 741203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 742c6fd2807SJeff Garzik 743203ef6c4STejun Heo if (offset) { 744203ef6c4STejun Heo *val = readl(port_mmio + offset); 745203ef6c4STejun Heo return 0; 746203ef6c4STejun Heo } 747da3dbb17STejun Heo return -EINVAL; 748c6fd2807SJeff Garzik } 749c6fd2807SJeff Garzik 750203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 751203ef6c4STejun Heo { 752203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 753203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 754203ef6c4STejun Heo 755203ef6c4STejun Heo if (offset) { 756203ef6c4STejun Heo writel(val, port_mmio + offset); 757da3dbb17STejun Heo return 0; 758c6fd2807SJeff Garzik } 759203ef6c4STejun Heo return -EINVAL; 760203ef6c4STejun Heo } 761c6fd2807SJeff Garzik 7624447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 763c6fd2807SJeff Garzik { 7644447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 765c6fd2807SJeff Garzik u32 tmp; 766c6fd2807SJeff Garzik 767c6fd2807SJeff Garzik /* start DMA */ 768c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 769c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 770c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 771c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 772c6fd2807SJeff Garzik } 773c6fd2807SJeff Garzik 7744447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 775c6fd2807SJeff Garzik { 7764447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 777c6fd2807SJeff Garzik u32 tmp; 778c6fd2807SJeff Garzik 779c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 780c6fd2807SJeff Garzik 781c6fd2807SJeff Garzik /* check if the HBA is idle */ 782c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 783c6fd2807SJeff Garzik return 0; 784c6fd2807SJeff Garzik 785c6fd2807SJeff Garzik /* setting HBA to idle */ 786c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 787c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 788c6fd2807SJeff Garzik 789c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 790c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 791c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 792c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 793c6fd2807SJeff Garzik return -EIO; 794c6fd2807SJeff Garzik 795c6fd2807SJeff Garzik return 0; 796c6fd2807SJeff Garzik } 797c6fd2807SJeff Garzik 7984447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 799c6fd2807SJeff Garzik { 8004447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 8014447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8024447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 803c6fd2807SJeff Garzik u32 tmp; 804c6fd2807SJeff Garzik 805c6fd2807SJeff Garzik /* set FIS registers */ 8064447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8074447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 8084447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 8094447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 810c6fd2807SJeff Garzik 8114447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8124447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 8134447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 8144447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 815c6fd2807SJeff Garzik 816c6fd2807SJeff Garzik /* enable FIS reception */ 817c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 818c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 819c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 820c6fd2807SJeff Garzik 821c6fd2807SJeff Garzik /* flush */ 822c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 823c6fd2807SJeff Garzik } 824c6fd2807SJeff Garzik 8254447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 826c6fd2807SJeff Garzik { 8274447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 828c6fd2807SJeff Garzik u32 tmp; 829c6fd2807SJeff Garzik 830c6fd2807SJeff Garzik /* disable FIS reception */ 831c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 832c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 833c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 834c6fd2807SJeff Garzik 835c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 836c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 837c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 838c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 839c6fd2807SJeff Garzik return -EBUSY; 840c6fd2807SJeff Garzik 841c6fd2807SJeff Garzik return 0; 842c6fd2807SJeff Garzik } 843c6fd2807SJeff Garzik 8444447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 845c6fd2807SJeff Garzik { 8464447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8474447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 848c6fd2807SJeff Garzik u32 cmd; 849c6fd2807SJeff Garzik 850c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 851c6fd2807SJeff Garzik 852c6fd2807SJeff Garzik /* spin up device */ 8534447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 854c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 855c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 856c6fd2807SJeff Garzik } 857c6fd2807SJeff Garzik 858c6fd2807SJeff Garzik /* wake up link */ 859c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 860c6fd2807SJeff Garzik } 861c6fd2807SJeff Garzik 86231556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap) 86331556594SKristen Carlson Accardi { 86431556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 86531556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 86631556594SKristen Carlson Accardi u32 cmd; 86731556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 86831556594SKristen Carlson Accardi 86931556594SKristen Carlson Accardi /* IPM bits should be disabled by libata-core */ 87031556594SKristen Carlson Accardi /* get the existing command bits */ 87131556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 87231556594SKristen Carlson Accardi 87331556594SKristen Carlson Accardi /* disable ALPM and ASP */ 87431556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ASP; 87531556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ALPE; 87631556594SKristen Carlson Accardi 87731556594SKristen Carlson Accardi /* force the interface back to active */ 87831556594SKristen Carlson Accardi cmd |= PORT_CMD_ICC_ACTIVE; 87931556594SKristen Carlson Accardi 88031556594SKristen Carlson Accardi /* write out new cmd value */ 88131556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 88231556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 88331556594SKristen Carlson Accardi 88431556594SKristen Carlson Accardi /* wait 10ms to be sure we've come out of any low power state */ 88531556594SKristen Carlson Accardi msleep(10); 88631556594SKristen Carlson Accardi 88731556594SKristen Carlson Accardi /* clear out any PhyRdy stuff from interrupt status */ 88831556594SKristen Carlson Accardi writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); 88931556594SKristen Carlson Accardi 89031556594SKristen Carlson Accardi /* go ahead and clean out PhyRdy Change from Serror too */ 89131556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 89231556594SKristen Carlson Accardi 89331556594SKristen Carlson Accardi /* 89431556594SKristen Carlson Accardi * Clear flag to indicate that we should ignore all PhyRdy 89531556594SKristen Carlson Accardi * state changes 89631556594SKristen Carlson Accardi */ 89731556594SKristen Carlson Accardi hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; 89831556594SKristen Carlson Accardi 89931556594SKristen Carlson Accardi /* 90031556594SKristen Carlson Accardi * Enable interrupts on Phy Ready. 90131556594SKristen Carlson Accardi */ 90231556594SKristen Carlson Accardi pp->intr_mask |= PORT_IRQ_PHYRDY; 90331556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 90431556594SKristen Carlson Accardi 90531556594SKristen Carlson Accardi /* 90631556594SKristen Carlson Accardi * don't change the link pm policy - we can be called 90731556594SKristen Carlson Accardi * just to turn of link pm temporarily 90831556594SKristen Carlson Accardi */ 90931556594SKristen Carlson Accardi } 91031556594SKristen Carlson Accardi 91131556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 91231556594SKristen Carlson Accardi enum link_pm policy) 91331556594SKristen Carlson Accardi { 91431556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 91531556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 91631556594SKristen Carlson Accardi u32 cmd; 91731556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 91831556594SKristen Carlson Accardi u32 asp; 91931556594SKristen Carlson Accardi 92031556594SKristen Carlson Accardi /* Make sure the host is capable of link power management */ 92131556594SKristen Carlson Accardi if (!(hpriv->cap & HOST_CAP_ALPM)) 92231556594SKristen Carlson Accardi return -EINVAL; 92331556594SKristen Carlson Accardi 92431556594SKristen Carlson Accardi switch (policy) { 92531556594SKristen Carlson Accardi case MAX_PERFORMANCE: 92631556594SKristen Carlson Accardi case NOT_AVAILABLE: 92731556594SKristen Carlson Accardi /* 92831556594SKristen Carlson Accardi * if we came here with NOT_AVAILABLE, 92931556594SKristen Carlson Accardi * it just means this is the first time we 93031556594SKristen Carlson Accardi * have tried to enable - default to max performance, 93131556594SKristen Carlson Accardi * and let the user go to lower power modes on request. 93231556594SKristen Carlson Accardi */ 93331556594SKristen Carlson Accardi ahci_disable_alpm(ap); 93431556594SKristen Carlson Accardi return 0; 93531556594SKristen Carlson Accardi case MIN_POWER: 93631556594SKristen Carlson Accardi /* configure HBA to enter SLUMBER */ 93731556594SKristen Carlson Accardi asp = PORT_CMD_ASP; 93831556594SKristen Carlson Accardi break; 93931556594SKristen Carlson Accardi case MEDIUM_POWER: 94031556594SKristen Carlson Accardi /* configure HBA to enter PARTIAL */ 94131556594SKristen Carlson Accardi asp = 0; 94231556594SKristen Carlson Accardi break; 94331556594SKristen Carlson Accardi default: 94431556594SKristen Carlson Accardi return -EINVAL; 94531556594SKristen Carlson Accardi } 94631556594SKristen Carlson Accardi 94731556594SKristen Carlson Accardi /* 94831556594SKristen Carlson Accardi * Disable interrupts on Phy Ready. This keeps us from 94931556594SKristen Carlson Accardi * getting woken up due to spurious phy ready interrupts 95031556594SKristen Carlson Accardi * TBD - Hot plug should be done via polling now, is 95131556594SKristen Carlson Accardi * that even supported? 95231556594SKristen Carlson Accardi */ 95331556594SKristen Carlson Accardi pp->intr_mask &= ~PORT_IRQ_PHYRDY; 95431556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 95531556594SKristen Carlson Accardi 95631556594SKristen Carlson Accardi /* 95731556594SKristen Carlson Accardi * Set a flag to indicate that we should ignore all PhyRdy 95831556594SKristen Carlson Accardi * state changes since these can happen now whenever we 95931556594SKristen Carlson Accardi * change link state 96031556594SKristen Carlson Accardi */ 96131556594SKristen Carlson Accardi hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; 96231556594SKristen Carlson Accardi 96331556594SKristen Carlson Accardi /* get the existing command bits */ 96431556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 96531556594SKristen Carlson Accardi 96631556594SKristen Carlson Accardi /* 96731556594SKristen Carlson Accardi * Set ASP based on Policy 96831556594SKristen Carlson Accardi */ 96931556594SKristen Carlson Accardi cmd |= asp; 97031556594SKristen Carlson Accardi 97131556594SKristen Carlson Accardi /* 97231556594SKristen Carlson Accardi * Setting this bit will instruct the HBA to aggressively 97331556594SKristen Carlson Accardi * enter a lower power link state when it's appropriate and 97431556594SKristen Carlson Accardi * based on the value set above for ASP 97531556594SKristen Carlson Accardi */ 97631556594SKristen Carlson Accardi cmd |= PORT_CMD_ALPE; 97731556594SKristen Carlson Accardi 97831556594SKristen Carlson Accardi /* write out new cmd value */ 97931556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 98031556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 98131556594SKristen Carlson Accardi 98231556594SKristen Carlson Accardi /* IPM bits should be set by libata-core */ 98331556594SKristen Carlson Accardi return 0; 98431556594SKristen Carlson Accardi } 98531556594SKristen Carlson Accardi 986438ac6d5STejun Heo #ifdef CONFIG_PM 9874447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 988c6fd2807SJeff Garzik { 9894447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 9904447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 991c6fd2807SJeff Garzik u32 cmd, scontrol; 992c6fd2807SJeff Garzik 9934447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 99407c53dacSTejun Heo return; 995c6fd2807SJeff Garzik 99607c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 997c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 998c6fd2807SJeff Garzik scontrol &= ~0xf; 999c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 1000c6fd2807SJeff Garzik 1001c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 100207c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 1003c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 1004c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 1005c6fd2807SJeff Garzik } 1006438ac6d5STejun Heo #endif 1007c6fd2807SJeff Garzik 1008df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap) 1009c6fd2807SJeff Garzik { 1010c6fd2807SJeff Garzik /* enable FIS reception */ 10114447d351STejun Heo ahci_start_fis_rx(ap); 1012c6fd2807SJeff Garzik 1013c6fd2807SJeff Garzik /* enable DMA */ 10144447d351STejun Heo ahci_start_engine(ap); 1015c6fd2807SJeff Garzik } 1016c6fd2807SJeff Garzik 10174447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 1018c6fd2807SJeff Garzik { 1019c6fd2807SJeff Garzik int rc; 1020c6fd2807SJeff Garzik 1021c6fd2807SJeff Garzik /* disable DMA */ 10224447d351STejun Heo rc = ahci_stop_engine(ap); 1023c6fd2807SJeff Garzik if (rc) { 1024c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 1025c6fd2807SJeff Garzik return rc; 1026c6fd2807SJeff Garzik } 1027c6fd2807SJeff Garzik 1028c6fd2807SJeff Garzik /* disable FIS reception */ 10294447d351STejun Heo rc = ahci_stop_fis_rx(ap); 1030c6fd2807SJeff Garzik if (rc) { 1031c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 1032c6fd2807SJeff Garzik return rc; 1033c6fd2807SJeff Garzik } 1034c6fd2807SJeff Garzik 1035c6fd2807SJeff Garzik return 0; 1036c6fd2807SJeff Garzik } 1037c6fd2807SJeff Garzik 10384447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 1039c6fd2807SJeff Garzik { 10404447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 104149f29090STejun Heo struct ahci_host_priv *hpriv = host->private_data; 10424447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1043d447df14STejun Heo u32 tmp; 1044c6fd2807SJeff Garzik 10453cc3eb11SJeff Garzik /* we must be in AHCI mode, before using anything 10463cc3eb11SJeff Garzik * AHCI-specific, such as HOST_RESET. 10473cc3eb11SJeff Garzik */ 1048b710a1f4STejun Heo ahci_enable_ahci(mmio); 10493cc3eb11SJeff Garzik 10503cc3eb11SJeff Garzik /* global controller reset */ 1051a22e6444STejun Heo if (!ahci_skip_host_reset) { 1052b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 1053c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 1054c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 1055c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1056c6fd2807SJeff Garzik } 1057c6fd2807SJeff Garzik 1058c6fd2807SJeff Garzik /* reset must complete within 1 second, or 1059c6fd2807SJeff Garzik * the hardware should be considered fried. 1060c6fd2807SJeff Garzik */ 1061c6fd2807SJeff Garzik ssleep(1); 1062c6fd2807SJeff Garzik 1063c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1064c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 10654447d351STejun Heo dev_printk(KERN_ERR, host->dev, 1066c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 1067c6fd2807SJeff Garzik return -EIO; 1068c6fd2807SJeff Garzik } 1069c6fd2807SJeff Garzik 107098fa4b60STejun Heo /* turn on AHCI mode */ 1071b710a1f4STejun Heo ahci_enable_ahci(mmio); 107298fa4b60STejun Heo 1073a22e6444STejun Heo /* Some registers might be cleared on reset. Restore 1074a22e6444STejun Heo * initial values. 1075a22e6444STejun Heo */ 10764447d351STejun Heo ahci_restore_initial_config(host); 1077a22e6444STejun Heo } else 1078a22e6444STejun Heo dev_printk(KERN_INFO, host->dev, 1079a22e6444STejun Heo "skipping global host reset\n"); 1080c6fd2807SJeff Garzik 1081c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 1082c6fd2807SJeff Garzik u16 tmp16; 1083c6fd2807SJeff Garzik 1084c6fd2807SJeff Garzik /* configure PCS */ 1085c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 108649f29090STejun Heo if ((tmp16 & hpriv->port_map) != hpriv->port_map) { 108749f29090STejun Heo tmp16 |= hpriv->port_map; 1088c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 1089c6fd2807SJeff Garzik } 109049f29090STejun Heo } 1091c6fd2807SJeff Garzik 1092c6fd2807SJeff Garzik return 0; 1093c6fd2807SJeff Garzik } 1094c6fd2807SJeff Garzik 10952bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, 10962bcd866bSJeff Garzik int port_no, void __iomem *mmio, 10972bcd866bSJeff Garzik void __iomem *port_mmio) 1098c6fd2807SJeff Garzik { 1099c6fd2807SJeff Garzik const char *emsg = NULL; 11002bcd866bSJeff Garzik int rc; 11012bcd866bSJeff Garzik u32 tmp; 1102c6fd2807SJeff Garzik 1103c6fd2807SJeff Garzik /* make sure port is not active */ 11044447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1105c6fd2807SJeff Garzik if (rc) 1106c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 1107c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 1108c6fd2807SJeff Garzik 1109c6fd2807SJeff Garzik /* clear SError */ 1110c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 1111c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 1112c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 1113c6fd2807SJeff Garzik 1114c6fd2807SJeff Garzik /* clear port IRQ */ 1115c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1116c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1117c6fd2807SJeff Garzik if (tmp) 1118c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1119c6fd2807SJeff Garzik 11202bcd866bSJeff Garzik writel(1 << port_no, mmio + HOST_IRQ_STAT); 11212bcd866bSJeff Garzik } 11222bcd866bSJeff Garzik 11232bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host) 11242bcd866bSJeff Garzik { 1125417a1a6dSTejun Heo struct ahci_host_priv *hpriv = host->private_data; 11262bcd866bSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 11272bcd866bSJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 11282bcd866bSJeff Garzik int i; 1129cd70c266SJeff Garzik void __iomem *port_mmio; 11302bcd866bSJeff Garzik u32 tmp; 1131c40e7cb8SJose Alberto Reguero int mv; 11322bcd866bSJeff Garzik 1133417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 1134c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 1135c40e7cb8SJose Alberto Reguero mv = 2; 1136c40e7cb8SJose Alberto Reguero else 1137c40e7cb8SJose Alberto Reguero mv = 4; 1138c40e7cb8SJose Alberto Reguero port_mmio = __ahci_port_base(host, mv); 1139cd70c266SJeff Garzik 1140cd70c266SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1141cd70c266SJeff Garzik 1142cd70c266SJeff Garzik /* clear port IRQ */ 1143cd70c266SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1144cd70c266SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1145cd70c266SJeff Garzik if (tmp) 1146cd70c266SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1147cd70c266SJeff Garzik } 1148cd70c266SJeff Garzik 11492bcd866bSJeff Garzik for (i = 0; i < host->n_ports; i++) { 11502bcd866bSJeff Garzik struct ata_port *ap = host->ports[i]; 11512bcd866bSJeff Garzik 1152cd70c266SJeff Garzik port_mmio = ahci_port_base(ap); 11532bcd866bSJeff Garzik if (ata_port_is_dummy(ap)) 11542bcd866bSJeff Garzik continue; 11552bcd866bSJeff Garzik 11562bcd866bSJeff Garzik ahci_port_init(pdev, ap, i, mmio, port_mmio); 1157c6fd2807SJeff Garzik } 1158c6fd2807SJeff Garzik 1159c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1160c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1161c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 1162c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1163c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1164c6fd2807SJeff Garzik } 1165c6fd2807SJeff Garzik 1166a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev) 1167a878539eSJeff Garzik { 1168a878539eSJeff Garzik struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; 1169a878539eSJeff Garzik 11704cde32fcSJeff Garzik if (hpriv->flags & AHCI_HFLAG_SECT255) { 1171a878539eSJeff Garzik dev->max_sectors = 255; 11724cde32fcSJeff Garzik ata_dev_printk(dev, KERN_INFO, 11734cde32fcSJeff Garzik "SB600 AHCI: limiting to 255 sectors per cmd\n"); 11744cde32fcSJeff Garzik } 1175a878539eSJeff Garzik } 1176a878539eSJeff Garzik 1177c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 1178c6fd2807SJeff Garzik { 11794447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1180c6fd2807SJeff Garzik struct ata_taskfile tf; 1181c6fd2807SJeff Garzik u32 tmp; 1182c6fd2807SJeff Garzik 1183c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 1184c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 1185c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 1186c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 1187c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 1188c6fd2807SJeff Garzik 1189c6fd2807SJeff Garzik return ata_dev_classify(&tf); 1190c6fd2807SJeff Garzik } 1191c6fd2807SJeff Garzik 1192c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 1193c6fd2807SJeff Garzik u32 opts) 1194c6fd2807SJeff Garzik { 1195c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 1196c6fd2807SJeff Garzik 1197c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 1198c6fd2807SJeff Garzik 1199c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 1200c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 1201c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 1202c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 1203c6fd2807SJeff Garzik } 1204c6fd2807SJeff Garzik 1205d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart) 1206c6fd2807SJeff Garzik { 1207350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1208cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1209520d06f9STejun Heo u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1210c6fd2807SJeff Garzik u32 tmp; 1211d2e75dffSTejun Heo int busy, rc; 1212c6fd2807SJeff Garzik 1213d2e75dffSTejun Heo /* do we need to kick the port? */ 1214520d06f9STejun Heo busy = status & (ATA_BUSY | ATA_DRQ); 1215d2e75dffSTejun Heo if (!busy && !force_restart) 1216d2e75dffSTejun Heo return 0; 1217c6fd2807SJeff Garzik 1218d2e75dffSTejun Heo /* stop engine */ 1219d2e75dffSTejun Heo rc = ahci_stop_engine(ap); 1220d2e75dffSTejun Heo if (rc) 1221d2e75dffSTejun Heo goto out_restart; 1222d2e75dffSTejun Heo 1223d2e75dffSTejun Heo /* need to do CLO? */ 1224d2e75dffSTejun Heo if (!busy) { 1225d2e75dffSTejun Heo rc = 0; 1226d2e75dffSTejun Heo goto out_restart; 1227d2e75dffSTejun Heo } 1228d2e75dffSTejun Heo 1229d2e75dffSTejun Heo if (!(hpriv->cap & HOST_CAP_CLO)) { 1230d2e75dffSTejun Heo rc = -EOPNOTSUPP; 1231d2e75dffSTejun Heo goto out_restart; 1232d2e75dffSTejun Heo } 1233d2e75dffSTejun Heo 1234d2e75dffSTejun Heo /* perform CLO */ 1235c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 1236c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 1237c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 1238c6fd2807SJeff Garzik 1239d2e75dffSTejun Heo rc = 0; 1240c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 1241c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 1242c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 1243d2e75dffSTejun Heo rc = -EIO; 1244c6fd2807SJeff Garzik 1245d2e75dffSTejun Heo /* restart engine */ 1246d2e75dffSTejun Heo out_restart: 1247d2e75dffSTejun Heo ahci_start_engine(ap); 1248d2e75dffSTejun Heo return rc; 1249c6fd2807SJeff Garzik } 1250c6fd2807SJeff Garzik 125191c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, 125291c4a2e0STejun Heo struct ata_taskfile *tf, int is_cmd, u16 flags, 125391c4a2e0STejun Heo unsigned long timeout_msec) 125491c4a2e0STejun Heo { 125591c4a2e0STejun Heo const u32 cmd_fis_len = 5; /* five dwords */ 125691c4a2e0STejun Heo struct ahci_port_priv *pp = ap->private_data; 125791c4a2e0STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 125891c4a2e0STejun Heo u8 *fis = pp->cmd_tbl; 125991c4a2e0STejun Heo u32 tmp; 126091c4a2e0STejun Heo 126191c4a2e0STejun Heo /* prep the command */ 126291c4a2e0STejun Heo ata_tf_to_fis(tf, pmp, is_cmd, fis); 126391c4a2e0STejun Heo ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); 126491c4a2e0STejun Heo 126591c4a2e0STejun Heo /* issue & wait */ 126691c4a2e0STejun Heo writel(1, port_mmio + PORT_CMD_ISSUE); 126791c4a2e0STejun Heo 126891c4a2e0STejun Heo if (timeout_msec) { 126991c4a2e0STejun Heo tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 127091c4a2e0STejun Heo 1, timeout_msec); 127191c4a2e0STejun Heo if (tmp & 0x1) { 127291c4a2e0STejun Heo ahci_kick_engine(ap, 1); 127391c4a2e0STejun Heo return -EBUSY; 127491c4a2e0STejun Heo } 127591c4a2e0STejun Heo } else 127691c4a2e0STejun Heo readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 127791c4a2e0STejun Heo 127891c4a2e0STejun Heo return 0; 127991c4a2e0STejun Heo } 128091c4a2e0STejun Heo 1281a89611e8STejun Heo static int ahci_check_ready(struct ata_link *link) 1282a89611e8STejun Heo { 1283350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(link->ap); 1284350756f6STejun Heo u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1285a89611e8STejun Heo 128678ab88f0STejun Heo return ata_check_ready(status); 1287a89611e8STejun Heo } 1288a89611e8STejun Heo 1289071f44b1STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class, 1290071f44b1STejun Heo unsigned long deadline) 1291c6fd2807SJeff Garzik { 1292cc0680a5STejun Heo struct ata_port *ap = link->ap; 1293071f44b1STejun Heo int pmp = sata_srst_pmp(link); 1294c6fd2807SJeff Garzik const char *reason = NULL; 12952cbb79ebSTejun Heo unsigned long now, msecs; 1296c6fd2807SJeff Garzik struct ata_taskfile tf; 1297c6fd2807SJeff Garzik int rc; 1298c6fd2807SJeff Garzik 1299c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1300c6fd2807SJeff Garzik 1301c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 1302d2e75dffSTejun Heo rc = ahci_kick_engine(ap, 1); 1303994056d7STejun Heo if (rc && rc != -EOPNOTSUPP) 1304cc0680a5STejun Heo ata_link_printk(link, KERN_WARNING, 1305994056d7STejun Heo "failed to reset engine (errno=%d)\n", rc); 1306c6fd2807SJeff Garzik 1307cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1308c6fd2807SJeff Garzik 1309c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 13102cbb79ebSTejun Heo msecs = 0; 13112cbb79ebSTejun Heo now = jiffies; 13122cbb79ebSTejun Heo if (time_after(now, deadline)) 13132cbb79ebSTejun Heo msecs = jiffies_to_msecs(deadline - now); 13142cbb79ebSTejun Heo 1315c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 1316a9cf5e85STejun Heo if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, 131791c4a2e0STejun Heo AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { 1318c6fd2807SJeff Garzik rc = -EIO; 1319c6fd2807SJeff Garzik reason = "1st FIS failed"; 1320c6fd2807SJeff Garzik goto fail; 1321c6fd2807SJeff Garzik } 1322c6fd2807SJeff Garzik 1323c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 1324c6fd2807SJeff Garzik msleep(1); 1325c6fd2807SJeff Garzik 1326c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 1327c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 1328a9cf5e85STejun Heo ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1329c6fd2807SJeff Garzik 1330705e76beSTejun Heo /* wait for link to become ready */ 1331a89611e8STejun Heo rc = ata_wait_after_reset(link, deadline, ahci_check_ready); 13329b89391cSTejun Heo /* link occupied, -ENODEV too is an error */ 13339b89391cSTejun Heo if (rc) { 1334c6fd2807SJeff Garzik reason = "device not ready"; 1335c6fd2807SJeff Garzik goto fail; 1336c6fd2807SJeff Garzik } 1337c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1338c6fd2807SJeff Garzik 1339c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 1340c6fd2807SJeff Garzik return 0; 1341c6fd2807SJeff Garzik 1342c6fd2807SJeff Garzik fail: 1343cc0680a5STejun Heo ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); 1344c6fd2807SJeff Garzik return rc; 1345c6fd2807SJeff Garzik } 1346c6fd2807SJeff Garzik 1347cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1348d4b2bab4STejun Heo unsigned long deadline) 1349c6fd2807SJeff Garzik { 13509dadd45bSTejun Heo const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); 1351cc0680a5STejun Heo struct ata_port *ap = link->ap; 1352c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1353c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1354c6fd2807SJeff Garzik struct ata_taskfile tf; 13559dadd45bSTejun Heo bool online; 1356c6fd2807SJeff Garzik int rc; 1357c6fd2807SJeff Garzik 1358c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1359c6fd2807SJeff Garzik 13604447d351STejun Heo ahci_stop_engine(ap); 1361c6fd2807SJeff Garzik 1362c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1363cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1364dfd7a3dbSTejun Heo tf.command = 0x80; 13659977126cSTejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1366c6fd2807SJeff Garzik 13679dadd45bSTejun Heo rc = sata_link_hardreset(link, timing, deadline, &online, 13689dadd45bSTejun Heo ahci_check_ready); 1369c6fd2807SJeff Garzik 13704447d351STejun Heo ahci_start_engine(ap); 1371c6fd2807SJeff Garzik 13729dadd45bSTejun Heo if (online) 13739dadd45bSTejun Heo *class = ahci_dev_classify(ap); 1374c6fd2807SJeff Garzik 1375c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1376c6fd2807SJeff Garzik return rc; 1377c6fd2807SJeff Garzik } 1378c6fd2807SJeff Garzik 1379cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 1380d4b2bab4STejun Heo unsigned long deadline) 1381ad616ffbSTejun Heo { 1382cc0680a5STejun Heo struct ata_port *ap = link->ap; 13839dadd45bSTejun Heo bool online; 1384ad616ffbSTejun Heo int rc; 1385ad616ffbSTejun Heo 1386ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1387ad616ffbSTejun Heo 13884447d351STejun Heo ahci_stop_engine(ap); 1389ad616ffbSTejun Heo 1390cc0680a5STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 13919dadd45bSTejun Heo deadline, &online, NULL); 1392ad616ffbSTejun Heo 13934447d351STejun Heo ahci_start_engine(ap); 1394ad616ffbSTejun Heo 1395ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1396ad616ffbSTejun Heo 1397ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1398ad616ffbSTejun Heo * request follow-up softreset. 1399ad616ffbSTejun Heo */ 14009dadd45bSTejun Heo return online ? -EAGAIN : rc; 1401ad616ffbSTejun Heo } 1402ad616ffbSTejun Heo 1403edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 1404edc93052STejun Heo unsigned long deadline) 1405edc93052STejun Heo { 1406edc93052STejun Heo struct ata_port *ap = link->ap; 1407edc93052STejun Heo struct ahci_port_priv *pp = ap->private_data; 1408edc93052STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1409edc93052STejun Heo struct ata_taskfile tf; 14109dadd45bSTejun Heo bool online; 1411edc93052STejun Heo int rc; 1412edc93052STejun Heo 1413edc93052STejun Heo ahci_stop_engine(ap); 1414edc93052STejun Heo 1415edc93052STejun Heo /* clear D2H reception area to properly wait for D2H FIS */ 1416edc93052STejun Heo ata_tf_init(link->device, &tf); 1417edc93052STejun Heo tf.command = 0x80; 1418edc93052STejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1419edc93052STejun Heo 1420edc93052STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 14219dadd45bSTejun Heo deadline, &online, NULL); 1422edc93052STejun Heo 1423edc93052STejun Heo ahci_start_engine(ap); 1424edc93052STejun Heo 1425edc93052STejun Heo /* The pseudo configuration device on SIMG4726 attached to 1426edc93052STejun Heo * ASUS P5W-DH Deluxe doesn't send signature FIS after 1427edc93052STejun Heo * hardreset if no device is attached to the first downstream 1428edc93052STejun Heo * port && the pseudo device locks up on SRST w/ PMP==0. To 1429edc93052STejun Heo * work around this, wait for !BSY only briefly. If BSY isn't 1430edc93052STejun Heo * cleared, perform CLO and proceed to IDENTIFY (achieved by 1431edc93052STejun Heo * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA). 1432edc93052STejun Heo * 1433edc93052STejun Heo * Wait for two seconds. Devices attached to downstream port 1434edc93052STejun Heo * which can't process the following IDENTIFY after this will 1435edc93052STejun Heo * have to be reset again. For most cases, this should 1436edc93052STejun Heo * suffice while making probing snappish enough. 1437edc93052STejun Heo */ 14389dadd45bSTejun Heo if (online) { 14399dadd45bSTejun Heo rc = ata_wait_after_reset(link, jiffies + 2 * HZ, 14409dadd45bSTejun Heo ahci_check_ready); 1441edc93052STejun Heo if (rc) 1442edc93052STejun Heo ahci_kick_engine(ap, 0); 14439dadd45bSTejun Heo } 14449dadd45bSTejun Heo return rc; 1445edc93052STejun Heo } 1446edc93052STejun Heo 1447cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class) 1448c6fd2807SJeff Garzik { 1449cc0680a5STejun Heo struct ata_port *ap = link->ap; 14504447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1451c6fd2807SJeff Garzik u32 new_tmp, tmp; 1452c6fd2807SJeff Garzik 1453203c75b8STejun Heo ata_std_postreset(link, class); 1454c6fd2807SJeff Garzik 1455c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1456c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1457c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1458c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1459c6fd2807SJeff Garzik else 1460c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1461c6fd2807SJeff Garzik if (new_tmp != tmp) { 1462c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1463c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1464c6fd2807SJeff Garzik } 1465c6fd2807SJeff Garzik } 1466c6fd2807SJeff Garzik 1467c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1468c6fd2807SJeff Garzik { 1469c6fd2807SJeff Garzik struct scatterlist *sg; 1470ff2aeb1eSTejun Heo struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1471ff2aeb1eSTejun Heo unsigned int si; 1472c6fd2807SJeff Garzik 1473c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1474c6fd2807SJeff Garzik 1475c6fd2807SJeff Garzik /* 1476c6fd2807SJeff Garzik * Next, the S/G list. 1477c6fd2807SJeff Garzik */ 1478ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) { 1479c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1480c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1481c6fd2807SJeff Garzik 1482ff2aeb1eSTejun Heo ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); 1483ff2aeb1eSTejun Heo ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); 1484ff2aeb1eSTejun Heo ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); 1485c6fd2807SJeff Garzik } 1486c6fd2807SJeff Garzik 1487ff2aeb1eSTejun Heo return si; 1488c6fd2807SJeff Garzik } 1489c6fd2807SJeff Garzik 1490c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1491c6fd2807SJeff Garzik { 1492c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1493c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1494405e66b3STejun Heo int is_atapi = ata_is_atapi(qc->tf.protocol); 1495c6fd2807SJeff Garzik void *cmd_tbl; 1496c6fd2807SJeff Garzik u32 opts; 1497c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1498c6fd2807SJeff Garzik unsigned int n_elem; 1499c6fd2807SJeff Garzik 1500c6fd2807SJeff Garzik /* 1501c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1502c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1503c6fd2807SJeff Garzik */ 1504c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1505c6fd2807SJeff Garzik 15067d50b60bSTejun Heo ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); 1507c6fd2807SJeff Garzik if (is_atapi) { 1508c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1509c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1510c6fd2807SJeff Garzik } 1511c6fd2807SJeff Garzik 1512c6fd2807SJeff Garzik n_elem = 0; 1513c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1514c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1515c6fd2807SJeff Garzik 1516c6fd2807SJeff Garzik /* 1517c6fd2807SJeff Garzik * Fill in command slot information. 1518c6fd2807SJeff Garzik */ 15197d50b60bSTejun Heo opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); 1520c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1521c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1522c6fd2807SJeff Garzik if (is_atapi) 1523c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1524c6fd2807SJeff Garzik 1525c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1526c6fd2807SJeff Garzik } 1527c6fd2807SJeff Garzik 1528c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1529c6fd2807SJeff Garzik { 1530417a1a6dSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1531c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 15327d50b60bSTejun Heo struct ata_eh_info *host_ehi = &ap->link.eh_info; 15337d50b60bSTejun Heo struct ata_link *link = NULL; 15347d50b60bSTejun Heo struct ata_queued_cmd *active_qc; 15357d50b60bSTejun Heo struct ata_eh_info *active_ehi; 1536c6fd2807SJeff Garzik u32 serror; 1537c6fd2807SJeff Garzik 15387d50b60bSTejun Heo /* determine active link */ 15397d50b60bSTejun Heo ata_port_for_each_link(link, ap) 15407d50b60bSTejun Heo if (ata_link_active(link)) 15417d50b60bSTejun Heo break; 15427d50b60bSTejun Heo if (!link) 15437d50b60bSTejun Heo link = &ap->link; 15447d50b60bSTejun Heo 15457d50b60bSTejun Heo active_qc = ata_qc_from_tag(ap, link->active_tag); 15467d50b60bSTejun Heo active_ehi = &link->eh_info; 15477d50b60bSTejun Heo 15487d50b60bSTejun Heo /* record irq stat */ 15497d50b60bSTejun Heo ata_ehi_clear_desc(host_ehi); 15507d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); 1551c6fd2807SJeff Garzik 1552c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1553da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1554c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 15557d50b60bSTejun Heo host_ehi->serror |= serror; 1556c6fd2807SJeff Garzik 155741669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 1558417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) 155941669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 156041669553STejun Heo 156155a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 15627d50b60bSTejun Heo /* If qc is active, charge it; otherwise, the active 15637d50b60bSTejun Heo * link. There's no active qc on NCQ errors. It will 15647d50b60bSTejun Heo * be determined by EH by reading log page 10h. 15657d50b60bSTejun Heo */ 15667d50b60bSTejun Heo if (active_qc) 15677d50b60bSTejun Heo active_qc->err_mask |= AC_ERR_DEV; 15687d50b60bSTejun Heo else 15697d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_DEV; 15707d50b60bSTejun Heo 1571417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) 15727d50b60bSTejun Heo host_ehi->serror &= ~SERR_INTERNAL; 1573c6fd2807SJeff Garzik } 1574c6fd2807SJeff Garzik 1575c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1576c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1577c6fd2807SJeff Garzik 15787d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1579cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 15807d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, 15817d50b60bSTejun Heo "unknown FIS %08x %08x %08x %08x" , 1582c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1583c6fd2807SJeff Garzik } 1584c6fd2807SJeff Garzik 1585071f44b1STejun Heo if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) { 15867d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1587cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 15887d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, "incorrect PMP"); 15897d50b60bSTejun Heo } 1590c6fd2807SJeff Garzik 15917d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 15927d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_HOST_BUS; 1593cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 15947d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "host bus error"); 15957d50b60bSTejun Heo } 15967d50b60bSTejun Heo 15977d50b60bSTejun Heo if (irq_stat & PORT_IRQ_IF_ERR) { 15987d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_ATA_BUS; 1599cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 16007d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "interface fatal error"); 16017d50b60bSTejun Heo } 16027d50b60bSTejun Heo 16037d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 16047d50b60bSTejun Heo ata_ehi_hotplugged(host_ehi); 16057d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "%s", 16067d50b60bSTejun Heo irq_stat & PORT_IRQ_CONNECT ? 16077d50b60bSTejun Heo "connection status changed" : "PHY RDY changed"); 16087d50b60bSTejun Heo } 16097d50b60bSTejun Heo 16107d50b60bSTejun Heo /* okay, let's hand over to EH */ 1611c6fd2807SJeff Garzik 1612c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1613c6fd2807SJeff Garzik ata_port_freeze(ap); 1614c6fd2807SJeff Garzik else 1615c6fd2807SJeff Garzik ata_port_abort(ap); 1616c6fd2807SJeff Garzik } 1617c6fd2807SJeff Garzik 1618df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap) 1619c6fd2807SJeff Garzik { 1620350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 16219af5c9c9STejun Heo struct ata_eh_info *ehi = &ap->link.eh_info; 16220291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 16235f226c6bSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1624b06ce3e5STejun Heo int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 1625c6fd2807SJeff Garzik u32 status, qc_active; 1626459ad688STejun Heo int rc; 1627c6fd2807SJeff Garzik 1628c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1629c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1630c6fd2807SJeff Garzik 1631b06ce3e5STejun Heo /* ignore BAD_PMP while resetting */ 1632b06ce3e5STejun Heo if (unlikely(resetting)) 1633b06ce3e5STejun Heo status &= ~PORT_IRQ_BAD_PMP; 1634b06ce3e5STejun Heo 163531556594SKristen Carlson Accardi /* If we are getting PhyRdy, this is 163631556594SKristen Carlson Accardi * just a power state change, we should 163731556594SKristen Carlson Accardi * clear out this, plus the PhyRdy/Comm 163831556594SKristen Carlson Accardi * Wake bits from Serror 163931556594SKristen Carlson Accardi */ 164031556594SKristen Carlson Accardi if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && 164131556594SKristen Carlson Accardi (status & PORT_IRQ_PHYRDY)) { 164231556594SKristen Carlson Accardi status &= ~PORT_IRQ_PHYRDY; 164331556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 164431556594SKristen Carlson Accardi } 164531556594SKristen Carlson Accardi 1646c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 1647c6fd2807SJeff Garzik ahci_error_intr(ap, status); 1648c6fd2807SJeff Garzik return; 1649c6fd2807SJeff Garzik } 1650c6fd2807SJeff Garzik 16512f294968SKristen Carlson Accardi if (status & PORT_IRQ_SDB_FIS) { 16525f226c6bSTejun Heo /* If SNotification is available, leave notification 16535f226c6bSTejun Heo * handling to sata_async_notification(). If not, 16545f226c6bSTejun Heo * emulate it by snooping SDB FIS RX area. 16555f226c6bSTejun Heo * 16565f226c6bSTejun Heo * Snooping FIS RX area is probably cheaper than 16575f226c6bSTejun Heo * poking SNotification but some constrollers which 16585f226c6bSTejun Heo * implement SNotification, ICH9 for example, don't 16595f226c6bSTejun Heo * store AN SDB FIS into receive area. 16605f226c6bSTejun Heo */ 16615f226c6bSTejun Heo if (hpriv->cap & HOST_CAP_SNTF) 16625f226c6bSTejun Heo sata_async_notification(ap); 16635f226c6bSTejun Heo else { 16645f226c6bSTejun Heo /* If the 'N' bit in word 0 of the FIS is set, 16655f226c6bSTejun Heo * we just received asynchronous notification. 16665f226c6bSTejun Heo * Tell libata about it. 16672f294968SKristen Carlson Accardi */ 16682f294968SKristen Carlson Accardi const __le32 *f = pp->rx_fis + RX_FIS_SDB; 16692f294968SKristen Carlson Accardi u32 f0 = le32_to_cpu(f[0]); 16702f294968SKristen Carlson Accardi 16717d77b247STejun Heo if (f0 & (1 << 15)) 16727d77b247STejun Heo sata_async_notification(ap); 16732f294968SKristen Carlson Accardi } 16745f226c6bSTejun Heo } 16752f294968SKristen Carlson Accardi 16767d50b60bSTejun Heo /* pp->active_link is valid iff any command is in flight */ 16777d50b60bSTejun Heo if (ap->qc_active && pp->active_link->sactive) 1678c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 1679c6fd2807SJeff Garzik else 1680c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 1681c6fd2807SJeff Garzik 168279f97dadSTejun Heo rc = ata_qc_complete_multiple(ap, qc_active); 1683b06ce3e5STejun Heo 1684459ad688STejun Heo /* while resetting, invalid completions are expected */ 1685459ad688STejun Heo if (unlikely(rc < 0 && !resetting)) { 1686c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 1687cf480626STejun Heo ehi->action |= ATA_EH_RESET; 1688c6fd2807SJeff Garzik ata_port_freeze(ap); 1689c6fd2807SJeff Garzik } 1690c6fd2807SJeff Garzik } 1691c6fd2807SJeff Garzik 16927d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 1693c6fd2807SJeff Garzik { 1694cca3974eSJeff Garzik struct ata_host *host = dev_instance; 1695c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 1696c6fd2807SJeff Garzik unsigned int i, handled = 0; 1697c6fd2807SJeff Garzik void __iomem *mmio; 1698c6fd2807SJeff Garzik u32 irq_stat, irq_ack = 0; 1699c6fd2807SJeff Garzik 1700c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1701c6fd2807SJeff Garzik 1702cca3974eSJeff Garzik hpriv = host->private_data; 17030d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 1704c6fd2807SJeff Garzik 1705c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 1706c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 1707c6fd2807SJeff Garzik irq_stat &= hpriv->port_map; 1708c6fd2807SJeff Garzik if (!irq_stat) 1709c6fd2807SJeff Garzik return IRQ_NONE; 1710c6fd2807SJeff Garzik 1711cca3974eSJeff Garzik spin_lock(&host->lock); 1712c6fd2807SJeff Garzik 1713cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 1714c6fd2807SJeff Garzik struct ata_port *ap; 1715c6fd2807SJeff Garzik 1716c6fd2807SJeff Garzik if (!(irq_stat & (1 << i))) 1717c6fd2807SJeff Garzik continue; 1718c6fd2807SJeff Garzik 1719cca3974eSJeff Garzik ap = host->ports[i]; 1720c6fd2807SJeff Garzik if (ap) { 1721df69c9c5SJeff Garzik ahci_port_intr(ap); 1722c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 1723c6fd2807SJeff Garzik } else { 1724c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 1725c6fd2807SJeff Garzik if (ata_ratelimit()) 1726cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 1727c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 1728c6fd2807SJeff Garzik } 1729c6fd2807SJeff Garzik 1730c6fd2807SJeff Garzik irq_ack |= (1 << i); 1731c6fd2807SJeff Garzik } 1732c6fd2807SJeff Garzik 1733c6fd2807SJeff Garzik if (irq_ack) { 1734c6fd2807SJeff Garzik writel(irq_ack, mmio + HOST_IRQ_STAT); 1735c6fd2807SJeff Garzik handled = 1; 1736c6fd2807SJeff Garzik } 1737c6fd2807SJeff Garzik 1738cca3974eSJeff Garzik spin_unlock(&host->lock); 1739c6fd2807SJeff Garzik 1740c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 1741c6fd2807SJeff Garzik 1742c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 1743c6fd2807SJeff Garzik } 1744c6fd2807SJeff Garzik 1745c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 1746c6fd2807SJeff Garzik { 1747c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 17484447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 17497d50b60bSTejun Heo struct ahci_port_priv *pp = ap->private_data; 17507d50b60bSTejun Heo 17517d50b60bSTejun Heo /* Keep track of the currently active link. It will be used 17527d50b60bSTejun Heo * in completion path to determine whether NCQ phase is in 17537d50b60bSTejun Heo * progress. 17547d50b60bSTejun Heo */ 17557d50b60bSTejun Heo pp->active_link = qc->dev->link; 1756c6fd2807SJeff Garzik 1757c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 1758c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 1759c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 1760c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 1761c6fd2807SJeff Garzik 1762c6fd2807SJeff Garzik return 0; 1763c6fd2807SJeff Garzik } 1764c6fd2807SJeff Garzik 17654c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) 17664c9bf4e7STejun Heo { 17674c9bf4e7STejun Heo struct ahci_port_priv *pp = qc->ap->private_data; 17684c9bf4e7STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 17694c9bf4e7STejun Heo 17704c9bf4e7STejun Heo ata_tf_from_fis(d2h_fis, &qc->result_tf); 17714c9bf4e7STejun Heo return true; 17724c9bf4e7STejun Heo } 17734c9bf4e7STejun Heo 1774c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 1775c6fd2807SJeff Garzik { 17764447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1777c6fd2807SJeff Garzik 1778c6fd2807SJeff Garzik /* turn IRQ off */ 1779c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1780c6fd2807SJeff Garzik } 1781c6fd2807SJeff Garzik 1782c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 1783c6fd2807SJeff Garzik { 17840d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 17854447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1786c6fd2807SJeff Garzik u32 tmp; 1787a7384925SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1788c6fd2807SJeff Garzik 1789c6fd2807SJeff Garzik /* clear IRQ */ 1790c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1791c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1792a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 1793c6fd2807SJeff Garzik 17941c954a4dSTejun Heo /* turn IRQ back on */ 17951c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 1796c6fd2807SJeff Garzik } 1797c6fd2807SJeff Garzik 1798c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 1799c6fd2807SJeff Garzik { 1800c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 1801c6fd2807SJeff Garzik /* restart engine */ 18024447d351STejun Heo ahci_stop_engine(ap); 18034447d351STejun Heo ahci_start_engine(ap); 1804c6fd2807SJeff Garzik } 1805c6fd2807SJeff Garzik 1806a1efdabaSTejun Heo sata_pmp_error_handler(ap); 1807edc93052STejun Heo } 1808edc93052STejun Heo 1809c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1810c6fd2807SJeff Garzik { 1811c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1812c6fd2807SJeff Garzik 1813c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 1814d2e75dffSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) 1815d2e75dffSTejun Heo ahci_kick_engine(ap, 1); 1816c6fd2807SJeff Garzik } 1817c6fd2807SJeff Garzik 18187d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap) 18197d50b60bSTejun Heo { 18207d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 18211c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 18227d50b60bSTejun Heo u32 cmd; 18237d50b60bSTejun Heo 18247d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 18257d50b60bSTejun Heo cmd |= PORT_CMD_PMP; 18267d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 18271c954a4dSTejun Heo 18281c954a4dSTejun Heo pp->intr_mask |= PORT_IRQ_BAD_PMP; 18291c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 18307d50b60bSTejun Heo } 18317d50b60bSTejun Heo 18327d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap) 18337d50b60bSTejun Heo { 18347d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 18351c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 18367d50b60bSTejun Heo u32 cmd; 18377d50b60bSTejun Heo 18387d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 18397d50b60bSTejun Heo cmd &= ~PORT_CMD_PMP; 18407d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 18411c954a4dSTejun Heo 18421c954a4dSTejun Heo pp->intr_mask &= ~PORT_IRQ_BAD_PMP; 18431c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 18447d50b60bSTejun Heo } 18457d50b60bSTejun Heo 1846028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap) 1847028a2596SAlexey Dobriyan { 1848028a2596SAlexey Dobriyan ahci_power_up(ap); 1849028a2596SAlexey Dobriyan ahci_start_port(ap); 1850028a2596SAlexey Dobriyan 1851071f44b1STejun Heo if (sata_pmp_attached(ap)) 18527d50b60bSTejun Heo ahci_pmp_attach(ap); 18537d50b60bSTejun Heo else 18547d50b60bSTejun Heo ahci_pmp_detach(ap); 18557d50b60bSTejun Heo 1856028a2596SAlexey Dobriyan return 0; 1857028a2596SAlexey Dobriyan } 1858028a2596SAlexey Dobriyan 1859438ac6d5STejun Heo #ifdef CONFIG_PM 1860c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 1861c6fd2807SJeff Garzik { 1862c6fd2807SJeff Garzik const char *emsg = NULL; 1863c6fd2807SJeff Garzik int rc; 1864c6fd2807SJeff Garzik 18654447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 18668e16f941STejun Heo if (rc == 0) 18674447d351STejun Heo ahci_power_down(ap); 18688e16f941STejun Heo else { 1869c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 1870df69c9c5SJeff Garzik ahci_start_port(ap); 1871c6fd2807SJeff Garzik } 1872c6fd2807SJeff Garzik 1873c6fd2807SJeff Garzik return rc; 1874c6fd2807SJeff Garzik } 1875c6fd2807SJeff Garzik 1876c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 1877c6fd2807SJeff Garzik { 1878cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 18790d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1880c6fd2807SJeff Garzik u32 ctl; 1881c6fd2807SJeff Garzik 18823a2d5b70SRafael J. Wysocki if (mesg.event & PM_EVENT_SLEEP) { 1883c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 1884c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 1885c6fd2807SJeff Garzik * transition of the HBA to D3 state. 1886c6fd2807SJeff Garzik */ 1887c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 1888c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 1889c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 1890c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1891c6fd2807SJeff Garzik } 1892c6fd2807SJeff Garzik 1893c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 1894c6fd2807SJeff Garzik } 1895c6fd2807SJeff Garzik 1896c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 1897c6fd2807SJeff Garzik { 1898cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 1899c6fd2807SJeff Garzik int rc; 1900c6fd2807SJeff Garzik 1901553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 1902553c4aa6STejun Heo if (rc) 1903553c4aa6STejun Heo return rc; 1904c6fd2807SJeff Garzik 1905c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 19064447d351STejun Heo rc = ahci_reset_controller(host); 1907c6fd2807SJeff Garzik if (rc) 1908c6fd2807SJeff Garzik return rc; 1909c6fd2807SJeff Garzik 19104447d351STejun Heo ahci_init_controller(host); 1911c6fd2807SJeff Garzik } 1912c6fd2807SJeff Garzik 1913cca3974eSJeff Garzik ata_host_resume(host); 1914c6fd2807SJeff Garzik 1915c6fd2807SJeff Garzik return 0; 1916c6fd2807SJeff Garzik } 1917438ac6d5STejun Heo #endif 1918c6fd2807SJeff Garzik 1919c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 1920c6fd2807SJeff Garzik { 1921cca3974eSJeff Garzik struct device *dev = ap->host->dev; 1922c6fd2807SJeff Garzik struct ahci_port_priv *pp; 1923c6fd2807SJeff Garzik void *mem; 1924c6fd2807SJeff Garzik dma_addr_t mem_dma; 1925c6fd2807SJeff Garzik 192624dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 1927c6fd2807SJeff Garzik if (!pp) 1928c6fd2807SJeff Garzik return -ENOMEM; 1929c6fd2807SJeff Garzik 193024dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 193124dc5f33STejun Heo GFP_KERNEL); 193224dc5f33STejun Heo if (!mem) 1933c6fd2807SJeff Garzik return -ENOMEM; 1934c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 1935c6fd2807SJeff Garzik 1936c6fd2807SJeff Garzik /* 1937c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 1938c6fd2807SJeff Garzik * 32 bytes each in size 1939c6fd2807SJeff Garzik */ 1940c6fd2807SJeff Garzik pp->cmd_slot = mem; 1941c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 1942c6fd2807SJeff Garzik 1943c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 1944c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 1945c6fd2807SJeff Garzik 1946c6fd2807SJeff Garzik /* 1947c6fd2807SJeff Garzik * Second item: Received-FIS area 1948c6fd2807SJeff Garzik */ 1949c6fd2807SJeff Garzik pp->rx_fis = mem; 1950c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 1951c6fd2807SJeff Garzik 1952c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 1953c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 1954c6fd2807SJeff Garzik 1955c6fd2807SJeff Garzik /* 1956c6fd2807SJeff Garzik * Third item: data area for storing a single command 1957c6fd2807SJeff Garzik * and its scatter-gather table 1958c6fd2807SJeff Garzik */ 1959c6fd2807SJeff Garzik pp->cmd_tbl = mem; 1960c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 1961c6fd2807SJeff Garzik 1962a7384925SKristen Carlson Accardi /* 1963a7384925SKristen Carlson Accardi * Save off initial list of interrupts to be enabled. 1964a7384925SKristen Carlson Accardi * This could be changed later 1965a7384925SKristen Carlson Accardi */ 1966a7384925SKristen Carlson Accardi pp->intr_mask = DEF_PORT_IRQ; 1967a7384925SKristen Carlson Accardi 1968c6fd2807SJeff Garzik ap->private_data = pp; 1969c6fd2807SJeff Garzik 1970df69c9c5SJeff Garzik /* engage engines, captain */ 1971df69c9c5SJeff Garzik return ahci_port_resume(ap); 1972c6fd2807SJeff Garzik } 1973c6fd2807SJeff Garzik 1974c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 1975c6fd2807SJeff Garzik { 1976c6fd2807SJeff Garzik const char *emsg = NULL; 1977c6fd2807SJeff Garzik int rc; 1978c6fd2807SJeff Garzik 1979c6fd2807SJeff Garzik /* de-initialize port */ 19804447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1981c6fd2807SJeff Garzik if (rc) 1982c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 1983c6fd2807SJeff Garzik } 1984c6fd2807SJeff Garzik 19854447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 1986c6fd2807SJeff Garzik { 1987c6fd2807SJeff Garzik int rc; 1988c6fd2807SJeff Garzik 1989c6fd2807SJeff Garzik if (using_dac && 1990c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 1991c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 1992c6fd2807SJeff Garzik if (rc) { 1993c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 1994c6fd2807SJeff Garzik if (rc) { 1995c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 1996c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 1997c6fd2807SJeff Garzik return rc; 1998c6fd2807SJeff Garzik } 1999c6fd2807SJeff Garzik } 2000c6fd2807SJeff Garzik } else { 2001c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 2002c6fd2807SJeff Garzik if (rc) { 2003c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2004c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 2005c6fd2807SJeff Garzik return rc; 2006c6fd2807SJeff Garzik } 2007c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2008c6fd2807SJeff Garzik if (rc) { 2009c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2010c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 2011c6fd2807SJeff Garzik return rc; 2012c6fd2807SJeff Garzik } 2013c6fd2807SJeff Garzik } 2014c6fd2807SJeff Garzik return 0; 2015c6fd2807SJeff Garzik } 2016c6fd2807SJeff Garzik 20174447d351STejun Heo static void ahci_print_info(struct ata_host *host) 2018c6fd2807SJeff Garzik { 20194447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 20204447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 20214447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2022c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 2023c6fd2807SJeff Garzik const char *speed_s; 2024c6fd2807SJeff Garzik u16 cc; 2025c6fd2807SJeff Garzik const char *scc_s; 2026c6fd2807SJeff Garzik 2027c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 2028c6fd2807SJeff Garzik cap = hpriv->cap; 2029c6fd2807SJeff Garzik impl = hpriv->port_map; 2030c6fd2807SJeff Garzik 2031c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 2032c6fd2807SJeff Garzik if (speed == 1) 2033c6fd2807SJeff Garzik speed_s = "1.5"; 2034c6fd2807SJeff Garzik else if (speed == 2) 2035c6fd2807SJeff Garzik speed_s = "3"; 2036c6fd2807SJeff Garzik else 2037c6fd2807SJeff Garzik speed_s = "?"; 2038c6fd2807SJeff Garzik 2039c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 2040c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 2041c6fd2807SJeff Garzik scc_s = "IDE"; 2042c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 2043c6fd2807SJeff Garzik scc_s = "SATA"; 2044c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 2045c6fd2807SJeff Garzik scc_s = "RAID"; 2046c6fd2807SJeff Garzik else 2047c6fd2807SJeff Garzik scc_s = "unknown"; 2048c6fd2807SJeff Garzik 2049c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2050c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 2051c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 2052c6fd2807SJeff Garzik , 2053c6fd2807SJeff Garzik 2054c6fd2807SJeff Garzik (vers >> 24) & 0xff, 2055c6fd2807SJeff Garzik (vers >> 16) & 0xff, 2056c6fd2807SJeff Garzik (vers >> 8) & 0xff, 2057c6fd2807SJeff Garzik vers & 0xff, 2058c6fd2807SJeff Garzik 2059c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 2060c6fd2807SJeff Garzik (cap & 0x1f) + 1, 2061c6fd2807SJeff Garzik speed_s, 2062c6fd2807SJeff Garzik impl, 2063c6fd2807SJeff Garzik scc_s); 2064c6fd2807SJeff Garzik 2065c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2066c6fd2807SJeff Garzik "flags: " 2067203ef6c4STejun Heo "%s%s%s%s%s%s%s" 2068c6fd2807SJeff Garzik "%s%s%s%s%s%s%s\n" 2069c6fd2807SJeff Garzik , 2070c6fd2807SJeff Garzik 2071c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 2072c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 2073203ef6c4STejun Heo cap & (1 << 29) ? "sntf " : "", 2074c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 2075c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 2076c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 2077c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 2078c6fd2807SJeff Garzik 2079c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 2080c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 2081c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 2082c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 2083c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 2084c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 2085c6fd2807SJeff Garzik cap & (1 << 13) ? "part " : "" 2086c6fd2807SJeff Garzik ); 2087c6fd2807SJeff Garzik } 2088c6fd2807SJeff Garzik 2089edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is 2090edc93052STejun Heo * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't 2091edc93052STejun Heo * support PMP and the 4726 either directly exports the device 2092edc93052STejun Heo * attached to the first downstream port or acts as a hardware storage 2093edc93052STejun Heo * controller and emulate a single ATA device (can be RAID 0/1 or some 2094edc93052STejun Heo * other configuration). 2095edc93052STejun Heo * 2096edc93052STejun Heo * When there's no device attached to the first downstream port of the 2097edc93052STejun Heo * 4726, "Config Disk" appears, which is a pseudo ATA device to 2098edc93052STejun Heo * configure the 4726. However, ATA emulation of the device is very 2099edc93052STejun Heo * lame. It doesn't send signature D2H Reg FIS after the initial 2100edc93052STejun Heo * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. 2101edc93052STejun Heo * 2102edc93052STejun Heo * The following function works around the problem by always using 2103edc93052STejun Heo * hardreset on the port and not depending on receiving signature FIS 2104edc93052STejun Heo * afterward. If signature FIS isn't received soon, ATA class is 2105edc93052STejun Heo * assumed without follow-up softreset. 2106edc93052STejun Heo */ 2107edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host) 2108edc93052STejun Heo { 2109edc93052STejun Heo static struct dmi_system_id sysids[] = { 2110edc93052STejun Heo { 2111edc93052STejun Heo .ident = "P5W DH Deluxe", 2112edc93052STejun Heo .matches = { 2113edc93052STejun Heo DMI_MATCH(DMI_SYS_VENDOR, 2114edc93052STejun Heo "ASUSTEK COMPUTER INC"), 2115edc93052STejun Heo DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), 2116edc93052STejun Heo }, 2117edc93052STejun Heo }, 2118edc93052STejun Heo { } 2119edc93052STejun Heo }; 2120edc93052STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 2121edc93052STejun Heo 2122edc93052STejun Heo if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) && 2123edc93052STejun Heo dmi_check_system(sysids)) { 2124edc93052STejun Heo struct ata_port *ap = host->ports[1]; 2125edc93052STejun Heo 2126edc93052STejun Heo dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " 2127edc93052STejun Heo "Deluxe on-board SIMG4726 workaround\n"); 2128edc93052STejun Heo 2129edc93052STejun Heo ap->ops = &ahci_p5wdh_ops; 2130edc93052STejun Heo ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; 2131edc93052STejun Heo } 2132edc93052STejun Heo } 2133edc93052STejun Heo 2134c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2135c6fd2807SJeff Garzik { 2136c6fd2807SJeff Garzik static int printed_version; 2137*e297d99eSTejun Heo unsigned int board_id = ent->driver_data; 2138*e297d99eSTejun Heo struct ata_port_info pi = ahci_port_info[board_id]; 21394447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 214024dc5f33STejun Heo struct device *dev = &pdev->dev; 2141c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 21424447d351STejun Heo struct ata_host *host; 2143837f5f8fSTejun Heo int n_ports, i, rc; 2144c6fd2807SJeff Garzik 2145c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2146c6fd2807SJeff Garzik 2147c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 2148c6fd2807SJeff Garzik 2149c6fd2807SJeff Garzik if (!printed_version++) 2150c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 2151c6fd2807SJeff Garzik 21524447d351STejun Heo /* acquire resources */ 215324dc5f33STejun Heo rc = pcim_enable_device(pdev); 2154c6fd2807SJeff Garzik if (rc) 2155c6fd2807SJeff Garzik return rc; 2156c6fd2807SJeff Garzik 2157dea55137STejun Heo /* AHCI controllers often implement SFF compatible interface. 2158dea55137STejun Heo * Grab all PCI BARs just in case. 2159dea55137STejun Heo */ 2160dea55137STejun Heo rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 21610d5ff566STejun Heo if (rc == -EBUSY) 216224dc5f33STejun Heo pcim_pin_device(pdev); 21630d5ff566STejun Heo if (rc) 216424dc5f33STejun Heo return rc; 2165c6fd2807SJeff Garzik 2166c4f7792cSTejun Heo if (pdev->vendor == PCI_VENDOR_ID_INTEL && 2167c4f7792cSTejun Heo (pdev->device == 0x2652 || pdev->device == 0x2653)) { 2168c4f7792cSTejun Heo u8 map; 2169c4f7792cSTejun Heo 2170c4f7792cSTejun Heo /* ICH6s share the same PCI ID for both piix and ahci 2171c4f7792cSTejun Heo * modes. Enabling ahci mode while MAP indicates 2172c4f7792cSTejun Heo * combined mode is a bad idea. Yield to ata_piix. 2173c4f7792cSTejun Heo */ 2174c4f7792cSTejun Heo pci_read_config_byte(pdev, ICH_MAP, &map); 2175c4f7792cSTejun Heo if (map & 0x3) { 2176c4f7792cSTejun Heo dev_printk(KERN_INFO, &pdev->dev, "controller is in " 2177c4f7792cSTejun Heo "combined mode, can't enable AHCI mode\n"); 2178c4f7792cSTejun Heo return -ENODEV; 2179c4f7792cSTejun Heo } 2180c4f7792cSTejun Heo } 2181c4f7792cSTejun Heo 218224dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 218324dc5f33STejun Heo if (!hpriv) 218424dc5f33STejun Heo return -ENOMEM; 2185417a1a6dSTejun Heo hpriv->flags |= (unsigned long)pi.private_data; 2186417a1a6dSTejun Heo 2187*e297d99eSTejun Heo /* MCP65 revision A1 and A2 can't do MSI */ 2188*e297d99eSTejun Heo if (board_id == board_ahci_mcp65 && 2189*e297d99eSTejun Heo (pdev->revision == 0xa1 || pdev->revision == 0xa2)) 2190*e297d99eSTejun Heo hpriv->flags |= AHCI_HFLAG_NO_MSI; 2191*e297d99eSTejun Heo 2192417a1a6dSTejun Heo if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) 2193417a1a6dSTejun Heo pci_intx(pdev, 1); 2194c6fd2807SJeff Garzik 21954447d351STejun Heo /* save initial config */ 2196417a1a6dSTejun Heo ahci_save_initial_config(pdev, hpriv); 2197c6fd2807SJeff Garzik 21984447d351STejun Heo /* prepare host */ 2199274c1fdeSTejun Heo if (hpriv->cap & HOST_CAP_NCQ) 22004447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 22014447d351STejun Heo 22027d50b60bSTejun Heo if (hpriv->cap & HOST_CAP_PMP) 22037d50b60bSTejun Heo pi.flags |= ATA_FLAG_PMP; 22047d50b60bSTejun Heo 2205837f5f8fSTejun Heo /* CAP.NP sometimes indicate the index of the last enabled 2206837f5f8fSTejun Heo * port, at other times, that of the last possible port, so 2207837f5f8fSTejun Heo * determining the maximum port number requires looking at 2208837f5f8fSTejun Heo * both CAP.NP and port_map. 2209837f5f8fSTejun Heo */ 2210837f5f8fSTejun Heo n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 2211837f5f8fSTejun Heo 2212837f5f8fSTejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 22134447d351STejun Heo if (!host) 22144447d351STejun Heo return -ENOMEM; 22154447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 22164447d351STejun Heo host->private_data = hpriv; 22174447d351STejun Heo 22184447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 22194447d351STejun Heo struct ata_port *ap = host->ports[i]; 22204447d351STejun Heo 2221cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); 2222cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, 2223cbcdd875STejun Heo 0x100 + ap->port_no * 0x80, "port"); 2224cbcdd875STejun Heo 222531556594SKristen Carlson Accardi /* set initial link pm policy */ 222631556594SKristen Carlson Accardi ap->pm_policy = NOT_AVAILABLE; 222731556594SKristen Carlson Accardi 2228dab632e8SJeff Garzik /* disabled/not-implemented port */ 2229350756f6STejun Heo if (!(hpriv->port_map & (1 << i))) 2230dab632e8SJeff Garzik ap->ops = &ata_dummy_port_ops; 22314447d351STejun Heo } 2232c6fd2807SJeff Garzik 2233edc93052STejun Heo /* apply workaround for ASUS P5W DH Deluxe mainboard */ 2234edc93052STejun Heo ahci_p5wdh_workaround(host); 2235edc93052STejun Heo 2236c6fd2807SJeff Garzik /* initialize adapter */ 22374447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2238c6fd2807SJeff Garzik if (rc) 223924dc5f33STejun Heo return rc; 2240c6fd2807SJeff Garzik 22414447d351STejun Heo rc = ahci_reset_controller(host); 22424447d351STejun Heo if (rc) 22434447d351STejun Heo return rc; 2244c6fd2807SJeff Garzik 22454447d351STejun Heo ahci_init_controller(host); 22464447d351STejun Heo ahci_print_info(host); 2247c6fd2807SJeff Garzik 22484447d351STejun Heo pci_set_master(pdev); 22494447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 22504447d351STejun Heo &ahci_sht); 2251c6fd2807SJeff Garzik } 2252c6fd2807SJeff Garzik 2253c6fd2807SJeff Garzik static int __init ahci_init(void) 2254c6fd2807SJeff Garzik { 2255c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 2256c6fd2807SJeff Garzik } 2257c6fd2807SJeff Garzik 2258c6fd2807SJeff Garzik static void __exit ahci_exit(void) 2259c6fd2807SJeff Garzik { 2260c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 2261c6fd2807SJeff Garzik } 2262c6fd2807SJeff Garzik 2263c6fd2807SJeff Garzik 2264c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 2265c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 2266c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2267c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 2268c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2269c6fd2807SJeff Garzik 2270c6fd2807SJeff Garzik module_init(ahci_init); 2271c6fd2807SJeff Garzik module_exit(ahci_exit); 2272