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); 59*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf); 60*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, 61*18f7ba4cSKristen Carlson Accardi size_t size); 62*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, 63*18f7ba4cSKristen Carlson Accardi ssize_t size); 64*18f7ba4cSKristen Carlson Accardi #define MAX_SLOTS 8 65c6fd2807SJeff Garzik 66c6fd2807SJeff Garzik enum { 67c6fd2807SJeff Garzik AHCI_PCI_BAR = 5, 68648a88beSTejun Heo AHCI_MAX_PORTS = 32, 69c6fd2807SJeff Garzik AHCI_MAX_SG = 168, /* hardware max is 64K */ 70c6fd2807SJeff Garzik AHCI_DMA_BOUNDARY = 0xffffffff, 71c6fd2807SJeff Garzik AHCI_MAX_CMDS = 32, 72c6fd2807SJeff Garzik AHCI_CMD_SZ = 32, 73c6fd2807SJeff Garzik AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, 74c6fd2807SJeff Garzik AHCI_RX_FIS_SZ = 256, 75c6fd2807SJeff Garzik AHCI_CMD_TBL_CDB = 0x40, 76c6fd2807SJeff Garzik AHCI_CMD_TBL_HDR_SZ = 0x80, 77c6fd2807SJeff Garzik AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), 78c6fd2807SJeff Garzik AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, 79c6fd2807SJeff Garzik AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + 80c6fd2807SJeff Garzik AHCI_RX_FIS_SZ, 81c6fd2807SJeff Garzik AHCI_IRQ_ON_SG = (1 << 31), 82c6fd2807SJeff Garzik AHCI_CMD_ATAPI = (1 << 5), 83c6fd2807SJeff Garzik AHCI_CMD_WRITE = (1 << 6), 84c6fd2807SJeff Garzik AHCI_CMD_PREFETCH = (1 << 7), 85c6fd2807SJeff Garzik AHCI_CMD_RESET = (1 << 8), 86c6fd2807SJeff Garzik AHCI_CMD_CLR_BUSY = (1 << 10), 87c6fd2807SJeff Garzik 88c6fd2807SJeff Garzik RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 890291f95fSTejun Heo RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 90c6fd2807SJeff Garzik RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ 91c6fd2807SJeff Garzik 92c6fd2807SJeff Garzik board_ahci = 0, 937a234affSTejun Heo board_ahci_vt8251 = 1, 947a234affSTejun Heo board_ahci_ign_iferr = 2, 957a234affSTejun Heo board_ahci_sb600 = 3, 967a234affSTejun Heo board_ahci_mv = 4, 97e39fc8c9SShane Huang board_ahci_sb700 = 5, 98e297d99eSTejun Heo board_ahci_mcp65 = 6, 999a3b103cSTejun Heo board_ahci_nopmp = 7, 100c6fd2807SJeff Garzik 101c6fd2807SJeff Garzik /* global controller registers */ 102c6fd2807SJeff Garzik HOST_CAP = 0x00, /* host capabilities */ 103c6fd2807SJeff Garzik HOST_CTL = 0x04, /* global host control */ 104c6fd2807SJeff Garzik HOST_IRQ_STAT = 0x08, /* interrupt status */ 105c6fd2807SJeff Garzik HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ 106c6fd2807SJeff Garzik HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ 107*18f7ba4cSKristen Carlson Accardi HOST_EM_LOC = 0x1c, /* Enclosure Management location */ 108*18f7ba4cSKristen Carlson Accardi HOST_EM_CTL = 0x20, /* Enclosure Management Control */ 109c6fd2807SJeff Garzik 110c6fd2807SJeff Garzik /* HOST_CTL bits */ 111c6fd2807SJeff Garzik HOST_RESET = (1 << 0), /* reset controller; self-clear */ 112c6fd2807SJeff Garzik HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ 113c6fd2807SJeff Garzik HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 114c6fd2807SJeff Garzik 115c6fd2807SJeff Garzik /* HOST_CAP bits */ 116*18f7ba4cSKristen Carlson Accardi HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ 117c6fd2807SJeff Garzik HOST_CAP_SSC = (1 << 14), /* Slumber capable */ 1187d50b60bSTejun Heo HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ 119c6fd2807SJeff Garzik HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 12031556594SKristen Carlson Accardi HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ 121c6fd2807SJeff Garzik HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ 122203ef6c4STejun Heo HOST_CAP_SNTF = (1 << 29), /* SNotification register */ 123c6fd2807SJeff Garzik HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 124c6fd2807SJeff Garzik HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 125c6fd2807SJeff Garzik 126c6fd2807SJeff Garzik /* registers for each SATA port */ 127c6fd2807SJeff Garzik PORT_LST_ADDR = 0x00, /* command list DMA addr */ 128c6fd2807SJeff Garzik PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ 129c6fd2807SJeff Garzik PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ 130c6fd2807SJeff Garzik PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ 131c6fd2807SJeff Garzik PORT_IRQ_STAT = 0x10, /* interrupt status */ 132c6fd2807SJeff Garzik PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ 133c6fd2807SJeff Garzik PORT_CMD = 0x18, /* port command */ 134c6fd2807SJeff Garzik PORT_TFDATA = 0x20, /* taskfile data */ 135c6fd2807SJeff Garzik PORT_SIG = 0x24, /* device TF signature */ 136c6fd2807SJeff Garzik PORT_CMD_ISSUE = 0x38, /* command issue */ 137c6fd2807SJeff Garzik PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ 138c6fd2807SJeff Garzik PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ 139c6fd2807SJeff Garzik PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ 140c6fd2807SJeff Garzik PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ 141203ef6c4STejun Heo PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ 142c6fd2807SJeff Garzik 143c6fd2807SJeff Garzik /* PORT_IRQ_{STAT,MASK} bits */ 144c6fd2807SJeff Garzik PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ 145c6fd2807SJeff Garzik PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ 146c6fd2807SJeff Garzik PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ 147c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ 148c6fd2807SJeff Garzik PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ 149c6fd2807SJeff Garzik PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ 150c6fd2807SJeff Garzik PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ 151c6fd2807SJeff Garzik PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ 152c6fd2807SJeff Garzik 153c6fd2807SJeff Garzik PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ 154c6fd2807SJeff Garzik PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ 155c6fd2807SJeff Garzik PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ 156c6fd2807SJeff Garzik PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ 157c6fd2807SJeff Garzik PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ 158c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ 159c6fd2807SJeff Garzik PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ 160c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ 161c6fd2807SJeff Garzik PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ 162c6fd2807SJeff Garzik 163c6fd2807SJeff Garzik PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 164c6fd2807SJeff Garzik PORT_IRQ_IF_ERR | 165c6fd2807SJeff Garzik PORT_IRQ_CONNECT | 166c6fd2807SJeff Garzik PORT_IRQ_PHYRDY | 1677d50b60bSTejun Heo PORT_IRQ_UNK_FIS | 1687d50b60bSTejun Heo PORT_IRQ_BAD_PMP, 169c6fd2807SJeff Garzik PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 170c6fd2807SJeff Garzik PORT_IRQ_TF_ERR | 171c6fd2807SJeff Garzik PORT_IRQ_HBUS_DATA_ERR, 172c6fd2807SJeff Garzik DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | 173c6fd2807SJeff Garzik PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | 174c6fd2807SJeff Garzik PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, 175c6fd2807SJeff Garzik 176c6fd2807SJeff Garzik /* PORT_CMD bits */ 17731556594SKristen Carlson Accardi PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ 17831556594SKristen Carlson Accardi PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ 179c6fd2807SJeff Garzik PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ 1807d50b60bSTejun Heo PORT_CMD_PMP = (1 << 17), /* PMP attached */ 181c6fd2807SJeff Garzik PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ 182c6fd2807SJeff Garzik PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ 183c6fd2807SJeff Garzik PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ 184c6fd2807SJeff Garzik PORT_CMD_CLO = (1 << 3), /* Command list override */ 185c6fd2807SJeff Garzik PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ 186c6fd2807SJeff Garzik PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 187c6fd2807SJeff Garzik PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 188c6fd2807SJeff Garzik 189c6fd2807SJeff Garzik PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ 190c6fd2807SJeff Garzik PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 191c6fd2807SJeff Garzik PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 192c6fd2807SJeff Garzik PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 193c6fd2807SJeff Garzik 194417a1a6dSTejun Heo /* hpriv->flags bits */ 195417a1a6dSTejun Heo AHCI_HFLAG_NO_NCQ = (1 << 0), 196417a1a6dSTejun Heo AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ 197417a1a6dSTejun Heo AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ 198417a1a6dSTejun Heo AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ 199417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ 200417a1a6dSTejun Heo AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ 2016949b914STejun Heo AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ 20231556594SKristen Carlson Accardi AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ 203a878539eSJeff Garzik AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ 204e297d99eSTejun Heo AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ 205417a1a6dSTejun Heo 206c6fd2807SJeff Garzik /* ap->flags bits */ 2071188c0d8STejun Heo 2081188c0d8STejun Heo AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 2091188c0d8STejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 21031556594SKristen Carlson Accardi ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | 21131556594SKristen Carlson Accardi ATA_FLAG_IPM, 212c4f7792cSTejun Heo 213c4f7792cSTejun Heo ICH_MAP = 0x90, /* ICH MAP register */ 214*18f7ba4cSKristen Carlson Accardi 215*18f7ba4cSKristen Carlson Accardi /* em_ctl bits */ 216*18f7ba4cSKristen Carlson Accardi EM_CTL_RST = (1 << 9), /* Reset */ 217*18f7ba4cSKristen Carlson Accardi EM_CTL_TM = (1 << 8), /* Transmit Message */ 218*18f7ba4cSKristen Carlson Accardi EM_CTL_ALHD = (1 << 26), /* Activity LED */ 219c6fd2807SJeff Garzik }; 220c6fd2807SJeff Garzik 221c6fd2807SJeff Garzik struct ahci_cmd_hdr { 2224ca4e439SAl Viro __le32 opts; 2234ca4e439SAl Viro __le32 status; 2244ca4e439SAl Viro __le32 tbl_addr; 2254ca4e439SAl Viro __le32 tbl_addr_hi; 2264ca4e439SAl Viro __le32 reserved[4]; 227c6fd2807SJeff Garzik }; 228c6fd2807SJeff Garzik 229c6fd2807SJeff Garzik struct ahci_sg { 2304ca4e439SAl Viro __le32 addr; 2314ca4e439SAl Viro __le32 addr_hi; 2324ca4e439SAl Viro __le32 reserved; 2334ca4e439SAl Viro __le32 flags_size; 234c6fd2807SJeff Garzik }; 235c6fd2807SJeff Garzik 236*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv { 237*18f7ba4cSKristen Carlson Accardi enum sw_activity blink_policy; 238*18f7ba4cSKristen Carlson Accardi struct timer_list timer; 239*18f7ba4cSKristen Carlson Accardi unsigned long saved_activity; 240*18f7ba4cSKristen Carlson Accardi unsigned long activity; 241*18f7ba4cSKristen Carlson Accardi unsigned long led_state; 242*18f7ba4cSKristen Carlson Accardi }; 243*18f7ba4cSKristen Carlson Accardi 244c6fd2807SJeff Garzik struct ahci_host_priv { 245417a1a6dSTejun Heo unsigned int flags; /* AHCI_HFLAG_* */ 246d447df14STejun Heo u32 cap; /* cap to use */ 247d447df14STejun Heo u32 port_map; /* port map to use */ 248d447df14STejun Heo u32 saved_cap; /* saved initial cap */ 249d447df14STejun Heo u32 saved_port_map; /* saved initial port_map */ 250*18f7ba4cSKristen Carlson Accardi u32 em_loc; /* enclosure management location */ 251c6fd2807SJeff Garzik }; 252c6fd2807SJeff Garzik 253c6fd2807SJeff Garzik struct ahci_port_priv { 2547d50b60bSTejun Heo struct ata_link *active_link; 255c6fd2807SJeff Garzik struct ahci_cmd_hdr *cmd_slot; 256c6fd2807SJeff Garzik dma_addr_t cmd_slot_dma; 257c6fd2807SJeff Garzik void *cmd_tbl; 258c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 259c6fd2807SJeff Garzik void *rx_fis; 260c6fd2807SJeff Garzik dma_addr_t rx_fis_dma; 2610291f95fSTejun Heo /* for NCQ spurious interrupt analysis */ 2620291f95fSTejun Heo unsigned int ncq_saw_d2h:1; 2630291f95fSTejun Heo unsigned int ncq_saw_dmas:1; 264afb2d552STejun Heo unsigned int ncq_saw_sdb:1; 265a7384925SKristen Carlson Accardi u32 intr_mask; /* interrupts to enable */ 266*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info 267*18f7ba4cSKristen Carlson Accardi * per PM slot */ 268c6fd2807SJeff Garzik }; 269c6fd2807SJeff Garzik 270da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); 271da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); 272c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 273c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 2744c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); 275c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap); 276c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap); 277c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc); 278c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap); 279c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap); 2807d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap); 2817d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap); 282a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class, 283a1efdabaSTejun Heo unsigned long deadline); 284bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, 285bd17243aSShane Huang unsigned long deadline); 286a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 287a1efdabaSTejun Heo unsigned long deadline); 288a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 289a1efdabaSTejun Heo unsigned long deadline); 290a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 291a1efdabaSTejun Heo unsigned long deadline); 292a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class); 293c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap); 294c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 295df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap); 296a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev); 297dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); 298dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 299dab632e8SJeff Garzik u32 opts); 300438ac6d5STejun Heo #ifdef CONFIG_PM 301c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); 302c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); 303c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev); 304438ac6d5STejun Heo #endif 305*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf); 306*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, 307*18f7ba4cSKristen Carlson Accardi enum sw_activity val); 308*18f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link); 309c6fd2807SJeff Garzik 310ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = { 311ee959b00STony Jones &dev_attr_link_power_management_policy, 312*18f7ba4cSKristen Carlson Accardi &dev_attr_em_message_type, 313*18f7ba4cSKristen Carlson Accardi &dev_attr_em_message, 314*18f7ba4cSKristen Carlson Accardi NULL 315*18f7ba4cSKristen Carlson Accardi }; 316*18f7ba4cSKristen Carlson Accardi 317*18f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = { 318*18f7ba4cSKristen Carlson Accardi &dev_attr_sw_activity, 31931556594SKristen Carlson Accardi NULL 32031556594SKristen Carlson Accardi }; 32131556594SKristen Carlson Accardi 322c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 32368d1d07bSTejun Heo ATA_NCQ_SHT(DRV_NAME), 324c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 325c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 326c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 32731556594SKristen Carlson Accardi .shost_attrs = ahci_shost_attrs, 328*18f7ba4cSKristen Carlson Accardi .sdev_attrs = ahci_sdev_attrs, 329c6fd2807SJeff Garzik }; 330c6fd2807SJeff Garzik 331029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = { 332029cfd6bSTejun Heo .inherits = &sata_pmp_port_ops, 333029cfd6bSTejun Heo 3347d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 335c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 336c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 3374c9bf4e7STejun Heo .qc_fill_rtf = ahci_qc_fill_rtf, 338c6fd2807SJeff Garzik 339c6fd2807SJeff Garzik .freeze = ahci_freeze, 340c6fd2807SJeff Garzik .thaw = ahci_thaw, 341a1efdabaSTejun Heo .softreset = ahci_softreset, 342a1efdabaSTejun Heo .hardreset = ahci_hardreset, 343a1efdabaSTejun Heo .postreset = ahci_postreset, 344071f44b1STejun Heo .pmp_softreset = ahci_softreset, 345c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 346c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 347029cfd6bSTejun Heo .dev_config = ahci_dev_config, 348c6fd2807SJeff Garzik 349029cfd6bSTejun Heo .scr_read = ahci_scr_read, 350029cfd6bSTejun Heo .scr_write = ahci_scr_write, 3517d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3527d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3537d50b60bSTejun Heo 354029cfd6bSTejun Heo .enable_pm = ahci_enable_alpm, 355029cfd6bSTejun Heo .disable_pm = ahci_disable_alpm, 356*18f7ba4cSKristen Carlson Accardi .em_show = ahci_led_show, 357*18f7ba4cSKristen Carlson Accardi .em_store = ahci_led_store, 358*18f7ba4cSKristen Carlson Accardi .sw_activity_show = ahci_activity_show, 359*18f7ba4cSKristen Carlson Accardi .sw_activity_store = ahci_activity_store, 360438ac6d5STejun Heo #ifdef CONFIG_PM 361c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 362c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 363438ac6d5STejun Heo #endif 364c6fd2807SJeff Garzik .port_start = ahci_port_start, 365c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 366c6fd2807SJeff Garzik }; 367c6fd2807SJeff Garzik 368029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = { 369029cfd6bSTejun Heo .inherits = &ahci_ops, 370a1efdabaSTejun Heo .hardreset = ahci_vt8251_hardreset, 371ad616ffbSTejun Heo }; 372ad616ffbSTejun Heo 373029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = { 374029cfd6bSTejun Heo .inherits = &ahci_ops, 375a1efdabaSTejun Heo .hardreset = ahci_p5wdh_hardreset, 376edc93052STejun Heo }; 377edc93052STejun Heo 378bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = { 379bd17243aSShane Huang .inherits = &ahci_ops, 380bd17243aSShane Huang .softreset = ahci_sb600_softreset, 381bd17243aSShane Huang .pmp_softreset = ahci_sb600_softreset, 382bd17243aSShane Huang }; 383bd17243aSShane Huang 384417a1a6dSTejun Heo #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 385417a1a6dSTejun Heo 386c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 387c6fd2807SJeff Garzik /* board_ahci */ 388c6fd2807SJeff Garzik { 3891188c0d8STejun Heo .flags = AHCI_FLAG_COMMON, 390c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 391469248abSJeff Garzik .udma_mask = ATA_UDMA6, 392c6fd2807SJeff Garzik .port_ops = &ahci_ops, 393c6fd2807SJeff Garzik }, 394c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 395c6fd2807SJeff Garzik { 3966949b914STejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), 397417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 398c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 399469248abSJeff Garzik .udma_mask = ATA_UDMA6, 400ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 401c6fd2807SJeff Garzik }, 40241669553STejun Heo /* board_ahci_ign_iferr */ 40341669553STejun Heo { 404417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), 405417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 40641669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 407469248abSJeff Garzik .udma_mask = ATA_UDMA6, 40841669553STejun Heo .port_ops = &ahci_ops, 40941669553STejun Heo }, 41055a61604SConke Hu /* board_ahci_sb600 */ 41155a61604SConke Hu { 412417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 41322b5e7a7STejun Heo AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | 414bd17243aSShane Huang AHCI_HFLAG_SECT255), 415417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 41655a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 417469248abSJeff Garzik .udma_mask = ATA_UDMA6, 418bd17243aSShane Huang .port_ops = &ahci_sb600_ops, 41955a61604SConke Hu }, 420cd70c266SJeff Garzik /* board_ahci_mv */ 421cd70c266SJeff Garzik { 422417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | 423417a1a6dSTejun Heo AHCI_HFLAG_MV_PATA), 424cd70c266SJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 425417a1a6dSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 426cd70c266SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 427cd70c266SJeff Garzik .udma_mask = ATA_UDMA6, 428cd70c266SJeff Garzik .port_ops = &ahci_ops, 429cd70c266SJeff Garzik }, 430e39fc8c9SShane Huang /* board_ahci_sb700 */ 431e39fc8c9SShane Huang { 432bd17243aSShane Huang AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), 433e39fc8c9SShane Huang .flags = AHCI_FLAG_COMMON, 434e39fc8c9SShane Huang .pio_mask = 0x1f, /* pio0-4 */ 435e39fc8c9SShane Huang .udma_mask = ATA_UDMA6, 436bd17243aSShane Huang .port_ops = &ahci_sb600_ops, 437e39fc8c9SShane Huang }, 438e297d99eSTejun Heo /* board_ahci_mcp65 */ 439e297d99eSTejun Heo { 440e297d99eSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), 441e297d99eSTejun Heo .flags = AHCI_FLAG_COMMON, 442e297d99eSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 443e297d99eSTejun Heo .udma_mask = ATA_UDMA6, 444e297d99eSTejun Heo .port_ops = &ahci_ops, 445e297d99eSTejun Heo }, 4469a3b103cSTejun Heo /* board_ahci_nopmp */ 4479a3b103cSTejun Heo { 4489a3b103cSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), 4499a3b103cSTejun Heo .flags = AHCI_FLAG_COMMON, 4509a3b103cSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 4519a3b103cSTejun Heo .udma_mask = ATA_UDMA6, 4529a3b103cSTejun Heo .port_ops = &ahci_ops, 4539a3b103cSTejun Heo }, 454c6fd2807SJeff Garzik }; 455c6fd2807SJeff Garzik 456c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 457c6fd2807SJeff Garzik /* Intel */ 45854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 45954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 46054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 46154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 46254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 46382490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 46454bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 46554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 46654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 46754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 4687a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ 4697a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ 4707a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ 4717a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ 4727a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ 4737a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ 4747a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ 4757a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ 4767a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ 4777a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ 4787a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ 4797a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ 4807a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ 4817a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ 4827a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ 4837a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ 4847a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ 485d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ 486d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ 48716ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ 48816ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ 489c6fd2807SJeff Garzik 490e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 491e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 492e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 493c6fd2807SJeff Garzik 494c6fd2807SJeff Garzik /* ATI */ 495c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 496e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */ 497e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */ 498e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */ 499e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */ 500e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ 501e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ 502c6fd2807SJeff Garzik 503c6fd2807SJeff Garzik /* VIA */ 50454bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 505bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 506c6fd2807SJeff Garzik 507c6fd2807SJeff Garzik /* NVIDIA */ 508e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */ 509e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */ 510e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */ 511e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */ 512e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */ 513e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */ 514e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */ 515e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */ 5166fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 5176fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 5186fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 5196fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 520895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 521895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 522895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 523895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 524895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 525895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 526895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 527895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 5280522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */ 5290522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */ 5300522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */ 5310522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */ 5320522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */ 5330522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */ 5340522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */ 5350522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */ 5360522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */ 5370522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */ 5380522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */ 5390522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */ 5400522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */ 5410522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */ 5420522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */ 5430522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */ 5440522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */ 5450522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */ 5460522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */ 5470522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */ 5480522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */ 5490522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ 5500522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ 5510522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ 5526ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */ 5536ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */ 5546ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */ 5556ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */ 5567100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ 5577100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ 5587100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ 5597100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ 5607100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ 5617100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ 5627100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ 5637100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ 56470d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */ 56570d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */ 56670d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */ 56770d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */ 56870d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */ 56970d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ 57070d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ 57170d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ 5723072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */ 5733072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */ 5743072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */ 5753072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */ 576c6fd2807SJeff Garzik 577c6fd2807SJeff Garzik /* SiS */ 5789a3b103cSTejun Heo { PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp }, /* SiS 966 */ 5799a3b103cSTejun Heo { PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp }, /* SiS 968 */ 5809a3b103cSTejun Heo { PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp }, /* SiS 968 */ 581c6fd2807SJeff Garzik 582cd70c266SJeff Garzik /* Marvell */ 583cd70c266SJeff Garzik { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ 584c40e7cb8SJose Alberto Reguero { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ 585cd70c266SJeff Garzik 586415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 587415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 588c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 589415ae2b5SJeff Garzik 590c6fd2807SJeff Garzik { } /* terminate list */ 591c6fd2807SJeff Garzik }; 592c6fd2807SJeff Garzik 593c6fd2807SJeff Garzik 594c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 595c6fd2807SJeff Garzik .name = DRV_NAME, 596c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 597c6fd2807SJeff Garzik .probe = ahci_init_one, 59824dc5f33STejun Heo .remove = ata_pci_remove_one, 599438ac6d5STejun Heo #ifdef CONFIG_PM 600c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 601c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 602438ac6d5STejun Heo #endif 603c6fd2807SJeff Garzik }; 604c6fd2807SJeff Garzik 605*18f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1; 606*18f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444); 607*18f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */ 608*18f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages, 609*18f7ba4cSKristen Carlson Accardi "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED"); 610c6fd2807SJeff Garzik 61198fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 61298fa4b60STejun Heo { 61398fa4b60STejun Heo return (cap & 0x1f) + 1; 61498fa4b60STejun Heo } 61598fa4b60STejun Heo 616dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host, 617dab632e8SJeff Garzik unsigned int port_no) 618dab632e8SJeff Garzik { 619dab632e8SJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 620dab632e8SJeff Garzik 621dab632e8SJeff Garzik return mmio + 0x100 + (port_no * 0x80); 622dab632e8SJeff Garzik } 623dab632e8SJeff Garzik 6244447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 625c6fd2807SJeff Garzik { 626dab632e8SJeff Garzik return __ahci_port_base(ap->host, ap->port_no); 627c6fd2807SJeff Garzik } 628c6fd2807SJeff Garzik 629b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio) 630b710a1f4STejun Heo { 63115fe982eSTejun Heo int i; 632b710a1f4STejun Heo u32 tmp; 633b710a1f4STejun Heo 634b710a1f4STejun Heo /* turn on AHCI_EN */ 635b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 63615fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 63715fe982eSTejun Heo return; 63815fe982eSTejun Heo 63915fe982eSTejun Heo /* Some controllers need AHCI_EN to be written multiple times. 64015fe982eSTejun Heo * Try a few times before giving up. 64115fe982eSTejun Heo */ 64215fe982eSTejun Heo for (i = 0; i < 5; i++) { 643b710a1f4STejun Heo tmp |= HOST_AHCI_EN; 644b710a1f4STejun Heo writel(tmp, mmio + HOST_CTL); 645b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ 64615fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 64715fe982eSTejun Heo return; 64815fe982eSTejun Heo msleep(10); 649b710a1f4STejun Heo } 65015fe982eSTejun Heo 65115fe982eSTejun Heo WARN_ON(1); 652b710a1f4STejun Heo } 653b710a1f4STejun Heo 654d447df14STejun Heo /** 655d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 6564447d351STejun Heo * @pdev: target PCI device 6574447d351STejun Heo * @hpriv: host private area to store config values 658d447df14STejun Heo * 659d447df14STejun Heo * Some registers containing configuration info might be setup by 660d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 661d447df14STejun Heo * initial values of those registers into @hpriv such that they 662d447df14STejun Heo * can be restored after controller reset. 663d447df14STejun Heo * 664d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 665d447df14STejun Heo * 666d447df14STejun Heo * LOCKING: 667d447df14STejun Heo * None. 668d447df14STejun Heo */ 6694447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 6704447d351STejun Heo struct ahci_host_priv *hpriv) 671d447df14STejun Heo { 6724447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 673d447df14STejun Heo u32 cap, port_map; 67417199b18STejun Heo int i; 675c40e7cb8SJose Alberto Reguero int mv; 676d447df14STejun Heo 677b710a1f4STejun Heo /* make sure AHCI mode is enabled before accessing CAP */ 678b710a1f4STejun Heo ahci_enable_ahci(mmio); 679b710a1f4STejun Heo 680d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 681d447df14STejun Heo * reset. Values without are used for driver operation. 682d447df14STejun Heo */ 683d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 684d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 685d447df14STejun Heo 686274c1fdeSTejun Heo /* some chips have errata preventing 64bit use */ 687417a1a6dSTejun Heo if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { 688c7a42156STejun Heo dev_printk(KERN_INFO, &pdev->dev, 689c7a42156STejun Heo "controller can't do 64bit DMA, forcing 32bit\n"); 690c7a42156STejun Heo cap &= ~HOST_CAP_64; 691c7a42156STejun Heo } 692c7a42156STejun Heo 693417a1a6dSTejun Heo if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { 694274c1fdeSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 695274c1fdeSTejun Heo "controller can't do NCQ, turning off CAP_NCQ\n"); 696274c1fdeSTejun Heo cap &= ~HOST_CAP_NCQ; 697274c1fdeSTejun Heo } 698274c1fdeSTejun Heo 699e297d99eSTejun Heo if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { 700e297d99eSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 701e297d99eSTejun Heo "controller can do NCQ, turning on CAP_NCQ\n"); 702e297d99eSTejun Heo cap |= HOST_CAP_NCQ; 703e297d99eSTejun Heo } 704e297d99eSTejun Heo 705258cd846SRoel Kluin if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { 7066949b914STejun Heo dev_printk(KERN_INFO, &pdev->dev, 7076949b914STejun Heo "controller can't do PMP, turning off CAP_PMP\n"); 7086949b914STejun Heo cap &= ~HOST_CAP_PMP; 7096949b914STejun Heo } 7106949b914STejun Heo 711d799e083STejun Heo if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && 712d799e083STejun Heo port_map != 1) { 713d799e083STejun Heo dev_printk(KERN_INFO, &pdev->dev, 714d799e083STejun Heo "JMB361 has only one port, port_map 0x%x -> 0x%x\n", 715d799e083STejun Heo port_map, 1); 716d799e083STejun Heo port_map = 1; 717d799e083STejun Heo } 718d799e083STejun Heo 719cd70c266SJeff Garzik /* 720cd70c266SJeff Garzik * Temporary Marvell 6145 hack: PATA port presence 721cd70c266SJeff Garzik * is asserted through the standard AHCI port 722cd70c266SJeff Garzik * presence register, as bit 4 (counting from 0) 723cd70c266SJeff Garzik */ 724417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 725c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 726c40e7cb8SJose Alberto Reguero mv = 0x3; 727c40e7cb8SJose Alberto Reguero else 728c40e7cb8SJose Alberto Reguero mv = 0xf; 729cd70c266SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 730cd70c266SJeff Garzik "MV_AHCI HACK: port_map %x -> %x\n", 731c40e7cb8SJose Alberto Reguero port_map, 732c40e7cb8SJose Alberto Reguero port_map & mv); 733cd70c266SJeff Garzik 734c40e7cb8SJose Alberto Reguero port_map &= mv; 735cd70c266SJeff Garzik } 736cd70c266SJeff Garzik 73717199b18STejun Heo /* cross check port_map and cap.n_ports */ 7387a234affSTejun Heo if (port_map) { 739837f5f8fSTejun Heo int map_ports = 0; 74017199b18STejun Heo 741837f5f8fSTejun Heo for (i = 0; i < AHCI_MAX_PORTS; i++) 742837f5f8fSTejun Heo if (port_map & (1 << i)) 743837f5f8fSTejun Heo map_ports++; 74417199b18STejun Heo 745837f5f8fSTejun Heo /* If PI has more ports than n_ports, whine, clear 746837f5f8fSTejun Heo * port_map and let it be generated from n_ports. 74717199b18STejun Heo */ 748837f5f8fSTejun Heo if (map_ports > ahci_nr_ports(cap)) { 7494447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 750837f5f8fSTejun Heo "implemented port map (0x%x) contains more " 751837f5f8fSTejun Heo "ports than nr_ports (%u), using nr_ports\n", 752837f5f8fSTejun Heo port_map, ahci_nr_ports(cap)); 7537a234affSTejun Heo port_map = 0; 7547a234affSTejun Heo } 7557a234affSTejun Heo } 7567a234affSTejun Heo 75717199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 7587a234affSTejun Heo if (!port_map) { 75917199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 7607a234affSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 7617a234affSTejun Heo "forcing PORTS_IMPL to 0x%x\n", port_map); 7627a234affSTejun Heo 7637a234affSTejun Heo /* write the fixed up value to the PI register */ 7647a234affSTejun Heo hpriv->saved_port_map = port_map; 76517199b18STejun Heo } 76617199b18STejun Heo 767d447df14STejun Heo /* record values to use during operation */ 768d447df14STejun Heo hpriv->cap = cap; 769d447df14STejun Heo hpriv->port_map = port_map; 770d447df14STejun Heo } 771d447df14STejun Heo 772d447df14STejun Heo /** 773d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 7744447d351STejun Heo * @host: target ATA host 775d447df14STejun Heo * 776d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 777d447df14STejun Heo * 778d447df14STejun Heo * LOCKING: 779d447df14STejun Heo * None. 780d447df14STejun Heo */ 7814447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 782d447df14STejun Heo { 7834447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 7844447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 7854447d351STejun Heo 786d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 787d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 788d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 789d447df14STejun Heo } 790d447df14STejun Heo 791203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) 792c6fd2807SJeff Garzik { 793203ef6c4STejun Heo static const int offset[] = { 794203ef6c4STejun Heo [SCR_STATUS] = PORT_SCR_STAT, 795203ef6c4STejun Heo [SCR_CONTROL] = PORT_SCR_CTL, 796203ef6c4STejun Heo [SCR_ERROR] = PORT_SCR_ERR, 797203ef6c4STejun Heo [SCR_ACTIVE] = PORT_SCR_ACT, 798203ef6c4STejun Heo [SCR_NOTIFICATION] = PORT_SCR_NTF, 799203ef6c4STejun Heo }; 800203ef6c4STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 801c6fd2807SJeff Garzik 802203ef6c4STejun Heo if (sc_reg < ARRAY_SIZE(offset) && 803203ef6c4STejun Heo (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) 804203ef6c4STejun Heo return offset[sc_reg]; 805da3dbb17STejun Heo return 0; 806c6fd2807SJeff Garzik } 807c6fd2807SJeff Garzik 808203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 809c6fd2807SJeff Garzik { 810203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 811203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 812c6fd2807SJeff Garzik 813203ef6c4STejun Heo if (offset) { 814203ef6c4STejun Heo *val = readl(port_mmio + offset); 815203ef6c4STejun Heo return 0; 816203ef6c4STejun Heo } 817da3dbb17STejun Heo return -EINVAL; 818c6fd2807SJeff Garzik } 819c6fd2807SJeff Garzik 820203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 821203ef6c4STejun Heo { 822203ef6c4STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 823203ef6c4STejun Heo int offset = ahci_scr_offset(ap, sc_reg); 824203ef6c4STejun Heo 825203ef6c4STejun Heo if (offset) { 826203ef6c4STejun Heo writel(val, port_mmio + offset); 827da3dbb17STejun Heo return 0; 828c6fd2807SJeff Garzik } 829203ef6c4STejun Heo return -EINVAL; 830203ef6c4STejun Heo } 831c6fd2807SJeff Garzik 8324447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 833c6fd2807SJeff Garzik { 8344447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 835c6fd2807SJeff Garzik u32 tmp; 836c6fd2807SJeff Garzik 837c6fd2807SJeff Garzik /* start DMA */ 838c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 839c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 840c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 841c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 842c6fd2807SJeff Garzik } 843c6fd2807SJeff Garzik 8444447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 845c6fd2807SJeff Garzik { 8464447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 847c6fd2807SJeff Garzik u32 tmp; 848c6fd2807SJeff Garzik 849c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 850c6fd2807SJeff Garzik 851c6fd2807SJeff Garzik /* check if the HBA is idle */ 852c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 853c6fd2807SJeff Garzik return 0; 854c6fd2807SJeff Garzik 855c6fd2807SJeff Garzik /* setting HBA to idle */ 856c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 857c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 858c6fd2807SJeff Garzik 859c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 860c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 861c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 862c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 863c6fd2807SJeff Garzik return -EIO; 864c6fd2807SJeff Garzik 865c6fd2807SJeff Garzik return 0; 866c6fd2807SJeff Garzik } 867c6fd2807SJeff Garzik 8684447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 869c6fd2807SJeff Garzik { 8704447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 8714447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8724447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 873c6fd2807SJeff Garzik u32 tmp; 874c6fd2807SJeff Garzik 875c6fd2807SJeff Garzik /* set FIS registers */ 8764447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8774447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 8784447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 8794447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 880c6fd2807SJeff Garzik 8814447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8824447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 8834447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 8844447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 885c6fd2807SJeff Garzik 886c6fd2807SJeff Garzik /* enable FIS reception */ 887c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 888c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 889c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 890c6fd2807SJeff Garzik 891c6fd2807SJeff Garzik /* flush */ 892c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 893c6fd2807SJeff Garzik } 894c6fd2807SJeff Garzik 8954447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 896c6fd2807SJeff Garzik { 8974447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 898c6fd2807SJeff Garzik u32 tmp; 899c6fd2807SJeff Garzik 900c6fd2807SJeff Garzik /* disable FIS reception */ 901c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 902c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 903c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 904c6fd2807SJeff Garzik 905c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 906c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 907c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 908c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 909c6fd2807SJeff Garzik return -EBUSY; 910c6fd2807SJeff Garzik 911c6fd2807SJeff Garzik return 0; 912c6fd2807SJeff Garzik } 913c6fd2807SJeff Garzik 9144447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 915c6fd2807SJeff Garzik { 9164447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 9174447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 918c6fd2807SJeff Garzik u32 cmd; 919c6fd2807SJeff Garzik 920c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 921c6fd2807SJeff Garzik 922c6fd2807SJeff Garzik /* spin up device */ 9234447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 924c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 925c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 926c6fd2807SJeff Garzik } 927c6fd2807SJeff Garzik 928c6fd2807SJeff Garzik /* wake up link */ 929c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 930c6fd2807SJeff Garzik } 931c6fd2807SJeff Garzik 93231556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap) 93331556594SKristen Carlson Accardi { 93431556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 93531556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 93631556594SKristen Carlson Accardi u32 cmd; 93731556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 93831556594SKristen Carlson Accardi 93931556594SKristen Carlson Accardi /* IPM bits should be disabled by libata-core */ 94031556594SKristen Carlson Accardi /* get the existing command bits */ 94131556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 94231556594SKristen Carlson Accardi 94331556594SKristen Carlson Accardi /* disable ALPM and ASP */ 94431556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ASP; 94531556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ALPE; 94631556594SKristen Carlson Accardi 94731556594SKristen Carlson Accardi /* force the interface back to active */ 94831556594SKristen Carlson Accardi cmd |= PORT_CMD_ICC_ACTIVE; 94931556594SKristen Carlson Accardi 95031556594SKristen Carlson Accardi /* write out new cmd value */ 95131556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 95231556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 95331556594SKristen Carlson Accardi 95431556594SKristen Carlson Accardi /* wait 10ms to be sure we've come out of any low power state */ 95531556594SKristen Carlson Accardi msleep(10); 95631556594SKristen Carlson Accardi 95731556594SKristen Carlson Accardi /* clear out any PhyRdy stuff from interrupt status */ 95831556594SKristen Carlson Accardi writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); 95931556594SKristen Carlson Accardi 96031556594SKristen Carlson Accardi /* go ahead and clean out PhyRdy Change from Serror too */ 96131556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 96231556594SKristen Carlson Accardi 96331556594SKristen Carlson Accardi /* 96431556594SKristen Carlson Accardi * Clear flag to indicate that we should ignore all PhyRdy 96531556594SKristen Carlson Accardi * state changes 96631556594SKristen Carlson Accardi */ 96731556594SKristen Carlson Accardi hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; 96831556594SKristen Carlson Accardi 96931556594SKristen Carlson Accardi /* 97031556594SKristen Carlson Accardi * Enable interrupts on Phy Ready. 97131556594SKristen Carlson Accardi */ 97231556594SKristen Carlson Accardi pp->intr_mask |= PORT_IRQ_PHYRDY; 97331556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 97431556594SKristen Carlson Accardi 97531556594SKristen Carlson Accardi /* 97631556594SKristen Carlson Accardi * don't change the link pm policy - we can be called 97731556594SKristen Carlson Accardi * just to turn of link pm temporarily 97831556594SKristen Carlson Accardi */ 97931556594SKristen Carlson Accardi } 98031556594SKristen Carlson Accardi 98131556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 98231556594SKristen Carlson Accardi enum link_pm policy) 98331556594SKristen Carlson Accardi { 98431556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 98531556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 98631556594SKristen Carlson Accardi u32 cmd; 98731556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 98831556594SKristen Carlson Accardi u32 asp; 98931556594SKristen Carlson Accardi 99031556594SKristen Carlson Accardi /* Make sure the host is capable of link power management */ 99131556594SKristen Carlson Accardi if (!(hpriv->cap & HOST_CAP_ALPM)) 99231556594SKristen Carlson Accardi return -EINVAL; 99331556594SKristen Carlson Accardi 99431556594SKristen Carlson Accardi switch (policy) { 99531556594SKristen Carlson Accardi case MAX_PERFORMANCE: 99631556594SKristen Carlson Accardi case NOT_AVAILABLE: 99731556594SKristen Carlson Accardi /* 99831556594SKristen Carlson Accardi * if we came here with NOT_AVAILABLE, 99931556594SKristen Carlson Accardi * it just means this is the first time we 100031556594SKristen Carlson Accardi * have tried to enable - default to max performance, 100131556594SKristen Carlson Accardi * and let the user go to lower power modes on request. 100231556594SKristen Carlson Accardi */ 100331556594SKristen Carlson Accardi ahci_disable_alpm(ap); 100431556594SKristen Carlson Accardi return 0; 100531556594SKristen Carlson Accardi case MIN_POWER: 100631556594SKristen Carlson Accardi /* configure HBA to enter SLUMBER */ 100731556594SKristen Carlson Accardi asp = PORT_CMD_ASP; 100831556594SKristen Carlson Accardi break; 100931556594SKristen Carlson Accardi case MEDIUM_POWER: 101031556594SKristen Carlson Accardi /* configure HBA to enter PARTIAL */ 101131556594SKristen Carlson Accardi asp = 0; 101231556594SKristen Carlson Accardi break; 101331556594SKristen Carlson Accardi default: 101431556594SKristen Carlson Accardi return -EINVAL; 101531556594SKristen Carlson Accardi } 101631556594SKristen Carlson Accardi 101731556594SKristen Carlson Accardi /* 101831556594SKristen Carlson Accardi * Disable interrupts on Phy Ready. This keeps us from 101931556594SKristen Carlson Accardi * getting woken up due to spurious phy ready interrupts 102031556594SKristen Carlson Accardi * TBD - Hot plug should be done via polling now, is 102131556594SKristen Carlson Accardi * that even supported? 102231556594SKristen Carlson Accardi */ 102331556594SKristen Carlson Accardi pp->intr_mask &= ~PORT_IRQ_PHYRDY; 102431556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 102531556594SKristen Carlson Accardi 102631556594SKristen Carlson Accardi /* 102731556594SKristen Carlson Accardi * Set a flag to indicate that we should ignore all PhyRdy 102831556594SKristen Carlson Accardi * state changes since these can happen now whenever we 102931556594SKristen Carlson Accardi * change link state 103031556594SKristen Carlson Accardi */ 103131556594SKristen Carlson Accardi hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; 103231556594SKristen Carlson Accardi 103331556594SKristen Carlson Accardi /* get the existing command bits */ 103431556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 103531556594SKristen Carlson Accardi 103631556594SKristen Carlson Accardi /* 103731556594SKristen Carlson Accardi * Set ASP based on Policy 103831556594SKristen Carlson Accardi */ 103931556594SKristen Carlson Accardi cmd |= asp; 104031556594SKristen Carlson Accardi 104131556594SKristen Carlson Accardi /* 104231556594SKristen Carlson Accardi * Setting this bit will instruct the HBA to aggressively 104331556594SKristen Carlson Accardi * enter a lower power link state when it's appropriate and 104431556594SKristen Carlson Accardi * based on the value set above for ASP 104531556594SKristen Carlson Accardi */ 104631556594SKristen Carlson Accardi cmd |= PORT_CMD_ALPE; 104731556594SKristen Carlson Accardi 104831556594SKristen Carlson Accardi /* write out new cmd value */ 104931556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 105031556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 105131556594SKristen Carlson Accardi 105231556594SKristen Carlson Accardi /* IPM bits should be set by libata-core */ 105331556594SKristen Carlson Accardi return 0; 105431556594SKristen Carlson Accardi } 105531556594SKristen Carlson Accardi 1056438ac6d5STejun Heo #ifdef CONFIG_PM 10574447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 1058c6fd2807SJeff Garzik { 10594447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 10604447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1061c6fd2807SJeff Garzik u32 cmd, scontrol; 1062c6fd2807SJeff Garzik 10634447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 106407c53dacSTejun Heo return; 1065c6fd2807SJeff Garzik 106607c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 1067c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 1068c6fd2807SJeff Garzik scontrol &= ~0xf; 1069c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 1070c6fd2807SJeff Garzik 1071c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 107207c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 1073c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 1074c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 1075c6fd2807SJeff Garzik } 1076438ac6d5STejun Heo #endif 1077c6fd2807SJeff Garzik 1078df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap) 1079c6fd2807SJeff Garzik { 1080*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1081*18f7ba4cSKristen Carlson Accardi struct ata_link *link; 1082*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 1083*18f7ba4cSKristen Carlson Accardi 1084c6fd2807SJeff Garzik /* enable FIS reception */ 10854447d351STejun Heo ahci_start_fis_rx(ap); 1086c6fd2807SJeff Garzik 1087c6fd2807SJeff Garzik /* enable DMA */ 10884447d351STejun Heo ahci_start_engine(ap); 1089*18f7ba4cSKristen Carlson Accardi 1090*18f7ba4cSKristen Carlson Accardi /* turn on LEDs */ 1091*18f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_EM) { 1092*18f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) { 1093*18f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[link->pmp]; 1094*18f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, emp->led_state, 4); 1095*18f7ba4cSKristen Carlson Accardi } 1096*18f7ba4cSKristen Carlson Accardi } 1097*18f7ba4cSKristen Carlson Accardi 1098*18f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_SW_ACTIVITY) 1099*18f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) 1100*18f7ba4cSKristen Carlson Accardi ahci_init_sw_activity(link); 1101*18f7ba4cSKristen Carlson Accardi 1102c6fd2807SJeff Garzik } 1103c6fd2807SJeff Garzik 11044447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 1105c6fd2807SJeff Garzik { 1106c6fd2807SJeff Garzik int rc; 1107c6fd2807SJeff Garzik 1108c6fd2807SJeff Garzik /* disable DMA */ 11094447d351STejun Heo rc = ahci_stop_engine(ap); 1110c6fd2807SJeff Garzik if (rc) { 1111c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 1112c6fd2807SJeff Garzik return rc; 1113c6fd2807SJeff Garzik } 1114c6fd2807SJeff Garzik 1115c6fd2807SJeff Garzik /* disable FIS reception */ 11164447d351STejun Heo rc = ahci_stop_fis_rx(ap); 1117c6fd2807SJeff Garzik if (rc) { 1118c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 1119c6fd2807SJeff Garzik return rc; 1120c6fd2807SJeff Garzik } 1121c6fd2807SJeff Garzik 1122c6fd2807SJeff Garzik return 0; 1123c6fd2807SJeff Garzik } 1124c6fd2807SJeff Garzik 11254447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 1126c6fd2807SJeff Garzik { 11274447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 112849f29090STejun Heo struct ahci_host_priv *hpriv = host->private_data; 11294447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1130d447df14STejun Heo u32 tmp; 1131c6fd2807SJeff Garzik 11323cc3eb11SJeff Garzik /* we must be in AHCI mode, before using anything 11333cc3eb11SJeff Garzik * AHCI-specific, such as HOST_RESET. 11343cc3eb11SJeff Garzik */ 1135b710a1f4STejun Heo ahci_enable_ahci(mmio); 11363cc3eb11SJeff Garzik 11373cc3eb11SJeff Garzik /* global controller reset */ 1138a22e6444STejun Heo if (!ahci_skip_host_reset) { 1139b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 1140c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 1141c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 1142c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1143c6fd2807SJeff Garzik } 1144c6fd2807SJeff Garzik 1145c6fd2807SJeff Garzik /* reset must complete within 1 second, or 1146c6fd2807SJeff Garzik * the hardware should be considered fried. 1147c6fd2807SJeff Garzik */ 1148c6fd2807SJeff Garzik ssleep(1); 1149c6fd2807SJeff Garzik 1150c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1151c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 11524447d351STejun Heo dev_printk(KERN_ERR, host->dev, 1153c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 1154c6fd2807SJeff Garzik return -EIO; 1155c6fd2807SJeff Garzik } 1156c6fd2807SJeff Garzik 115798fa4b60STejun Heo /* turn on AHCI mode */ 1158b710a1f4STejun Heo ahci_enable_ahci(mmio); 115998fa4b60STejun Heo 1160a22e6444STejun Heo /* Some registers might be cleared on reset. Restore 1161a22e6444STejun Heo * initial values. 1162a22e6444STejun Heo */ 11634447d351STejun Heo ahci_restore_initial_config(host); 1164a22e6444STejun Heo } else 1165a22e6444STejun Heo dev_printk(KERN_INFO, host->dev, 1166a22e6444STejun Heo "skipping global host reset\n"); 1167c6fd2807SJeff Garzik 1168c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 1169c6fd2807SJeff Garzik u16 tmp16; 1170c6fd2807SJeff Garzik 1171c6fd2807SJeff Garzik /* configure PCS */ 1172c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 117349f29090STejun Heo if ((tmp16 & hpriv->port_map) != hpriv->port_map) { 117449f29090STejun Heo tmp16 |= hpriv->port_map; 1175c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 1176c6fd2807SJeff Garzik } 117749f29090STejun Heo } 1178c6fd2807SJeff Garzik 1179c6fd2807SJeff Garzik return 0; 1180c6fd2807SJeff Garzik } 1181c6fd2807SJeff Garzik 1182*18f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link) 1183*18f7ba4cSKristen Carlson Accardi { 1184*18f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 1185*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1186*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 1187*18f7ba4cSKristen Carlson Accardi 1188*18f7ba4cSKristen Carlson Accardi if (!(link->flags & ATA_LFLAG_SW_ACTIVITY)) 1189*18f7ba4cSKristen Carlson Accardi return; 1190*18f7ba4cSKristen Carlson Accardi 1191*18f7ba4cSKristen Carlson Accardi emp->activity++; 1192*18f7ba4cSKristen Carlson Accardi if (!timer_pending(&emp->timer)) 1193*18f7ba4cSKristen Carlson Accardi mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10)); 1194*18f7ba4cSKristen Carlson Accardi } 1195*18f7ba4cSKristen Carlson Accardi 1196*18f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg) 1197*18f7ba4cSKristen Carlson Accardi { 1198*18f7ba4cSKristen Carlson Accardi struct ata_link *link = (struct ata_link *)arg; 1199*18f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 1200*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1201*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 1202*18f7ba4cSKristen Carlson Accardi unsigned long led_message = emp->led_state; 1203*18f7ba4cSKristen Carlson Accardi u32 activity_led_state; 1204*18f7ba4cSKristen Carlson Accardi 1205*18f7ba4cSKristen Carlson Accardi led_message &= 0xffff0000; 1206*18f7ba4cSKristen Carlson Accardi led_message |= ap->port_no | (link->pmp << 8); 1207*18f7ba4cSKristen Carlson Accardi 1208*18f7ba4cSKristen Carlson Accardi /* check to see if we've had activity. If so, 1209*18f7ba4cSKristen Carlson Accardi * toggle state of LED and reset timer. If not, 1210*18f7ba4cSKristen Carlson Accardi * turn LED to desired idle state. 1211*18f7ba4cSKristen Carlson Accardi */ 1212*18f7ba4cSKristen Carlson Accardi if (emp->saved_activity != emp->activity) { 1213*18f7ba4cSKristen Carlson Accardi emp->saved_activity = emp->activity; 1214*18f7ba4cSKristen Carlson Accardi /* get the current LED state */ 1215*18f7ba4cSKristen Carlson Accardi activity_led_state = led_message & 0x00010000; 1216*18f7ba4cSKristen Carlson Accardi 1217*18f7ba4cSKristen Carlson Accardi if (activity_led_state) 1218*18f7ba4cSKristen Carlson Accardi activity_led_state = 0; 1219*18f7ba4cSKristen Carlson Accardi else 1220*18f7ba4cSKristen Carlson Accardi activity_led_state = 1; 1221*18f7ba4cSKristen Carlson Accardi 1222*18f7ba4cSKristen Carlson Accardi /* clear old state */ 1223*18f7ba4cSKristen Carlson Accardi led_message &= 0xfff8ffff; 1224*18f7ba4cSKristen Carlson Accardi 1225*18f7ba4cSKristen Carlson Accardi /* toggle state */ 1226*18f7ba4cSKristen Carlson Accardi led_message |= (activity_led_state << 16); 1227*18f7ba4cSKristen Carlson Accardi mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100)); 1228*18f7ba4cSKristen Carlson Accardi } else { 1229*18f7ba4cSKristen Carlson Accardi /* switch to idle */ 1230*18f7ba4cSKristen Carlson Accardi led_message &= 0xfff8ffff; 1231*18f7ba4cSKristen Carlson Accardi if (emp->blink_policy == BLINK_OFF) 1232*18f7ba4cSKristen Carlson Accardi led_message |= (1 << 16); 1233*18f7ba4cSKristen Carlson Accardi } 1234*18f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, led_message, 4); 1235*18f7ba4cSKristen Carlson Accardi } 1236*18f7ba4cSKristen Carlson Accardi 1237*18f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link) 1238*18f7ba4cSKristen Carlson Accardi { 1239*18f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 1240*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1241*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 1242*18f7ba4cSKristen Carlson Accardi 1243*18f7ba4cSKristen Carlson Accardi /* init activity stats, setup timer */ 1244*18f7ba4cSKristen Carlson Accardi emp->saved_activity = emp->activity = 0; 1245*18f7ba4cSKristen Carlson Accardi setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link); 1246*18f7ba4cSKristen Carlson Accardi 1247*18f7ba4cSKristen Carlson Accardi /* check our blink policy and set flag for link if it's enabled */ 1248*18f7ba4cSKristen Carlson Accardi if (emp->blink_policy) 1249*18f7ba4cSKristen Carlson Accardi link->flags |= ATA_LFLAG_SW_ACTIVITY; 1250*18f7ba4cSKristen Carlson Accardi } 1251*18f7ba4cSKristen Carlson Accardi 1252*18f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host) 1253*18f7ba4cSKristen Carlson Accardi { 1254*18f7ba4cSKristen Carlson Accardi void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1255*18f7ba4cSKristen Carlson Accardi u32 em_ctl; 1256*18f7ba4cSKristen Carlson Accardi 1257*18f7ba4cSKristen Carlson Accardi em_ctl = readl(mmio + HOST_EM_CTL); 1258*18f7ba4cSKristen Carlson Accardi if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST)) 1259*18f7ba4cSKristen Carlson Accardi return -EINVAL; 1260*18f7ba4cSKristen Carlson Accardi 1261*18f7ba4cSKristen Carlson Accardi writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL); 1262*18f7ba4cSKristen Carlson Accardi return 0; 1263*18f7ba4cSKristen Carlson Accardi } 1264*18f7ba4cSKristen Carlson Accardi 1265*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, 1266*18f7ba4cSKristen Carlson Accardi ssize_t size) 1267*18f7ba4cSKristen Carlson Accardi { 1268*18f7ba4cSKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 1269*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1270*18f7ba4cSKristen Carlson Accardi void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 1271*18f7ba4cSKristen Carlson Accardi u32 em_ctl; 1272*18f7ba4cSKristen Carlson Accardi u32 message[] = {0, 0}; 1273*18f7ba4cSKristen Carlson Accardi unsigned int flags; 1274*18f7ba4cSKristen Carlson Accardi int pmp; 1275*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 1276*18f7ba4cSKristen Carlson Accardi 1277*18f7ba4cSKristen Carlson Accardi /* get the slot number from the message */ 1278*18f7ba4cSKristen Carlson Accardi pmp = (state & 0x0000ff00) >> 8; 1279*18f7ba4cSKristen Carlson Accardi if (pmp < MAX_SLOTS) 1280*18f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[pmp]; 1281*18f7ba4cSKristen Carlson Accardi else 1282*18f7ba4cSKristen Carlson Accardi return -EINVAL; 1283*18f7ba4cSKristen Carlson Accardi 1284*18f7ba4cSKristen Carlson Accardi spin_lock_irqsave(ap->lock, flags); 1285*18f7ba4cSKristen Carlson Accardi 1286*18f7ba4cSKristen Carlson Accardi /* 1287*18f7ba4cSKristen Carlson Accardi * if we are still busy transmitting a previous message, 1288*18f7ba4cSKristen Carlson Accardi * do not allow 1289*18f7ba4cSKristen Carlson Accardi */ 1290*18f7ba4cSKristen Carlson Accardi em_ctl = readl(mmio + HOST_EM_CTL); 1291*18f7ba4cSKristen Carlson Accardi if (em_ctl & EM_CTL_TM) { 1292*18f7ba4cSKristen Carlson Accardi spin_unlock_irqrestore(ap->lock, flags); 1293*18f7ba4cSKristen Carlson Accardi return -EINVAL; 1294*18f7ba4cSKristen Carlson Accardi } 1295*18f7ba4cSKristen Carlson Accardi 1296*18f7ba4cSKristen Carlson Accardi /* 1297*18f7ba4cSKristen Carlson Accardi * create message header - this is all zero except for 1298*18f7ba4cSKristen Carlson Accardi * the message size, which is 4 bytes. 1299*18f7ba4cSKristen Carlson Accardi */ 1300*18f7ba4cSKristen Carlson Accardi message[0] |= (4 << 8); 1301*18f7ba4cSKristen Carlson Accardi 1302*18f7ba4cSKristen Carlson Accardi /* ignore 0:4 of byte zero, fill in port info yourself */ 1303*18f7ba4cSKristen Carlson Accardi message[1] = ((state & 0xfffffff0) | ap->port_no); 1304*18f7ba4cSKristen Carlson Accardi 1305*18f7ba4cSKristen Carlson Accardi /* write message to EM_LOC */ 1306*18f7ba4cSKristen Carlson Accardi writel(message[0], mmio + hpriv->em_loc); 1307*18f7ba4cSKristen Carlson Accardi writel(message[1], mmio + hpriv->em_loc+4); 1308*18f7ba4cSKristen Carlson Accardi 1309*18f7ba4cSKristen Carlson Accardi /* save off new led state for port/slot */ 1310*18f7ba4cSKristen Carlson Accardi emp->led_state = message[1]; 1311*18f7ba4cSKristen Carlson Accardi 1312*18f7ba4cSKristen Carlson Accardi /* 1313*18f7ba4cSKristen Carlson Accardi * tell hardware to transmit the message 1314*18f7ba4cSKristen Carlson Accardi */ 1315*18f7ba4cSKristen Carlson Accardi writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); 1316*18f7ba4cSKristen Carlson Accardi 1317*18f7ba4cSKristen Carlson Accardi spin_unlock_irqrestore(ap->lock, flags); 1318*18f7ba4cSKristen Carlson Accardi return size; 1319*18f7ba4cSKristen Carlson Accardi } 1320*18f7ba4cSKristen Carlson Accardi 1321*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf) 1322*18f7ba4cSKristen Carlson Accardi { 1323*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1324*18f7ba4cSKristen Carlson Accardi struct ata_link *link; 1325*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 1326*18f7ba4cSKristen Carlson Accardi int rc = 0; 1327*18f7ba4cSKristen Carlson Accardi 1328*18f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) { 1329*18f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[link->pmp]; 1330*18f7ba4cSKristen Carlson Accardi rc += sprintf(buf, "%lx\n", emp->led_state); 1331*18f7ba4cSKristen Carlson Accardi } 1332*18f7ba4cSKristen Carlson Accardi return rc; 1333*18f7ba4cSKristen Carlson Accardi } 1334*18f7ba4cSKristen Carlson Accardi 1335*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, 1336*18f7ba4cSKristen Carlson Accardi size_t size) 1337*18f7ba4cSKristen Carlson Accardi { 1338*18f7ba4cSKristen Carlson Accardi int state; 1339*18f7ba4cSKristen Carlson Accardi int pmp; 1340*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1341*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 1342*18f7ba4cSKristen Carlson Accardi 1343*18f7ba4cSKristen Carlson Accardi state = simple_strtoul(buf, NULL, 0); 1344*18f7ba4cSKristen Carlson Accardi 1345*18f7ba4cSKristen Carlson Accardi /* get the slot number from the message */ 1346*18f7ba4cSKristen Carlson Accardi pmp = (state & 0x0000ff00) >> 8; 1347*18f7ba4cSKristen Carlson Accardi if (pmp < MAX_SLOTS) 1348*18f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[pmp]; 1349*18f7ba4cSKristen Carlson Accardi else 1350*18f7ba4cSKristen Carlson Accardi return -EINVAL; 1351*18f7ba4cSKristen Carlson Accardi 1352*18f7ba4cSKristen Carlson Accardi /* mask off the activity bits if we are in sw_activity 1353*18f7ba4cSKristen Carlson Accardi * mode, user should turn off sw_activity before setting 1354*18f7ba4cSKristen Carlson Accardi * activity led through em_message 1355*18f7ba4cSKristen Carlson Accardi */ 1356*18f7ba4cSKristen Carlson Accardi if (emp->blink_policy) 1357*18f7ba4cSKristen Carlson Accardi state &= 0xfff8ffff; 1358*18f7ba4cSKristen Carlson Accardi 1359*18f7ba4cSKristen Carlson Accardi return ahci_transmit_led_message(ap, state, size); 1360*18f7ba4cSKristen Carlson Accardi } 1361*18f7ba4cSKristen Carlson Accardi 1362*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val) 1363*18f7ba4cSKristen Carlson Accardi { 1364*18f7ba4cSKristen Carlson Accardi struct ata_link *link = dev->link; 1365*18f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 1366*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1367*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 1368*18f7ba4cSKristen Carlson Accardi u32 port_led_state = emp->led_state; 1369*18f7ba4cSKristen Carlson Accardi 1370*18f7ba4cSKristen Carlson Accardi /* save the desired Activity LED behavior */ 1371*18f7ba4cSKristen Carlson Accardi if (val == OFF) { 1372*18f7ba4cSKristen Carlson Accardi /* clear LFLAG */ 1373*18f7ba4cSKristen Carlson Accardi link->flags &= ~(ATA_LFLAG_SW_ACTIVITY); 1374*18f7ba4cSKristen Carlson Accardi 1375*18f7ba4cSKristen Carlson Accardi /* set the LED to OFF */ 1376*18f7ba4cSKristen Carlson Accardi port_led_state &= 0xfff80000; 1377*18f7ba4cSKristen Carlson Accardi port_led_state |= (ap->port_no | (link->pmp << 8)); 1378*18f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, port_led_state, 4); 1379*18f7ba4cSKristen Carlson Accardi } else { 1380*18f7ba4cSKristen Carlson Accardi link->flags |= ATA_LFLAG_SW_ACTIVITY; 1381*18f7ba4cSKristen Carlson Accardi if (val == BLINK_OFF) { 1382*18f7ba4cSKristen Carlson Accardi /* set LED to ON for idle */ 1383*18f7ba4cSKristen Carlson Accardi port_led_state &= 0xfff80000; 1384*18f7ba4cSKristen Carlson Accardi port_led_state |= (ap->port_no | (link->pmp << 8)); 1385*18f7ba4cSKristen Carlson Accardi port_led_state |= 0x00010000; /* check this */ 1386*18f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, port_led_state, 4); 1387*18f7ba4cSKristen Carlson Accardi } 1388*18f7ba4cSKristen Carlson Accardi } 1389*18f7ba4cSKristen Carlson Accardi emp->blink_policy = val; 1390*18f7ba4cSKristen Carlson Accardi return 0; 1391*18f7ba4cSKristen Carlson Accardi } 1392*18f7ba4cSKristen Carlson Accardi 1393*18f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) 1394*18f7ba4cSKristen Carlson Accardi { 1395*18f7ba4cSKristen Carlson Accardi struct ata_link *link = dev->link; 1396*18f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 1397*18f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 1398*18f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 1399*18f7ba4cSKristen Carlson Accardi 1400*18f7ba4cSKristen Carlson Accardi /* display the saved value of activity behavior for this 1401*18f7ba4cSKristen Carlson Accardi * disk. 1402*18f7ba4cSKristen Carlson Accardi */ 1403*18f7ba4cSKristen Carlson Accardi return sprintf(buf, "%d\n", emp->blink_policy); 1404*18f7ba4cSKristen Carlson Accardi } 1405*18f7ba4cSKristen Carlson Accardi 14062bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, 14072bcd866bSJeff Garzik int port_no, void __iomem *mmio, 14082bcd866bSJeff Garzik void __iomem *port_mmio) 1409c6fd2807SJeff Garzik { 1410c6fd2807SJeff Garzik const char *emsg = NULL; 14112bcd866bSJeff Garzik int rc; 14122bcd866bSJeff Garzik u32 tmp; 1413c6fd2807SJeff Garzik 1414c6fd2807SJeff Garzik /* make sure port is not active */ 14154447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1416c6fd2807SJeff Garzik if (rc) 1417c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 1418c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 1419c6fd2807SJeff Garzik 1420c6fd2807SJeff Garzik /* clear SError */ 1421c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 1422c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 1423c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 1424c6fd2807SJeff Garzik 1425c6fd2807SJeff Garzik /* clear port IRQ */ 1426c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1427c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1428c6fd2807SJeff Garzik if (tmp) 1429c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1430c6fd2807SJeff Garzik 14312bcd866bSJeff Garzik writel(1 << port_no, mmio + HOST_IRQ_STAT); 14322bcd866bSJeff Garzik } 14332bcd866bSJeff Garzik 14342bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host) 14352bcd866bSJeff Garzik { 1436417a1a6dSTejun Heo struct ahci_host_priv *hpriv = host->private_data; 14372bcd866bSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 14382bcd866bSJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 14392bcd866bSJeff Garzik int i; 1440cd70c266SJeff Garzik void __iomem *port_mmio; 14412bcd866bSJeff Garzik u32 tmp; 1442c40e7cb8SJose Alberto Reguero int mv; 14432bcd866bSJeff Garzik 1444417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 1445c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 1446c40e7cb8SJose Alberto Reguero mv = 2; 1447c40e7cb8SJose Alberto Reguero else 1448c40e7cb8SJose Alberto Reguero mv = 4; 1449c40e7cb8SJose Alberto Reguero port_mmio = __ahci_port_base(host, mv); 1450cd70c266SJeff Garzik 1451cd70c266SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1452cd70c266SJeff Garzik 1453cd70c266SJeff Garzik /* clear port IRQ */ 1454cd70c266SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1455cd70c266SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1456cd70c266SJeff Garzik if (tmp) 1457cd70c266SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1458cd70c266SJeff Garzik } 1459cd70c266SJeff Garzik 14602bcd866bSJeff Garzik for (i = 0; i < host->n_ports; i++) { 14612bcd866bSJeff Garzik struct ata_port *ap = host->ports[i]; 14622bcd866bSJeff Garzik 1463cd70c266SJeff Garzik port_mmio = ahci_port_base(ap); 14642bcd866bSJeff Garzik if (ata_port_is_dummy(ap)) 14652bcd866bSJeff Garzik continue; 14662bcd866bSJeff Garzik 14672bcd866bSJeff Garzik ahci_port_init(pdev, ap, i, mmio, port_mmio); 1468c6fd2807SJeff Garzik } 1469c6fd2807SJeff Garzik 1470c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1471c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1472c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 1473c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1474c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1475c6fd2807SJeff Garzik } 1476c6fd2807SJeff Garzik 1477a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev) 1478a878539eSJeff Garzik { 1479a878539eSJeff Garzik struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; 1480a878539eSJeff Garzik 14814cde32fcSJeff Garzik if (hpriv->flags & AHCI_HFLAG_SECT255) { 1482a878539eSJeff Garzik dev->max_sectors = 255; 14834cde32fcSJeff Garzik ata_dev_printk(dev, KERN_INFO, 14844cde32fcSJeff Garzik "SB600 AHCI: limiting to 255 sectors per cmd\n"); 14854cde32fcSJeff Garzik } 1486a878539eSJeff Garzik } 1487a878539eSJeff Garzik 1488c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 1489c6fd2807SJeff Garzik { 14904447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1491c6fd2807SJeff Garzik struct ata_taskfile tf; 1492c6fd2807SJeff Garzik u32 tmp; 1493c6fd2807SJeff Garzik 1494c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 1495c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 1496c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 1497c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 1498c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 1499c6fd2807SJeff Garzik 1500c6fd2807SJeff Garzik return ata_dev_classify(&tf); 1501c6fd2807SJeff Garzik } 1502c6fd2807SJeff Garzik 1503c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 1504c6fd2807SJeff Garzik u32 opts) 1505c6fd2807SJeff Garzik { 1506c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 1507c6fd2807SJeff Garzik 1508c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 1509c6fd2807SJeff Garzik 1510c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 1511c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 1512c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 1513c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 1514c6fd2807SJeff Garzik } 1515c6fd2807SJeff Garzik 1516d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart) 1517c6fd2807SJeff Garzik { 1518350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1519cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1520520d06f9STejun Heo u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1521c6fd2807SJeff Garzik u32 tmp; 1522d2e75dffSTejun Heo int busy, rc; 1523c6fd2807SJeff Garzik 1524d2e75dffSTejun Heo /* do we need to kick the port? */ 1525520d06f9STejun Heo busy = status & (ATA_BUSY | ATA_DRQ); 1526d2e75dffSTejun Heo if (!busy && !force_restart) 1527d2e75dffSTejun Heo return 0; 1528c6fd2807SJeff Garzik 1529d2e75dffSTejun Heo /* stop engine */ 1530d2e75dffSTejun Heo rc = ahci_stop_engine(ap); 1531d2e75dffSTejun Heo if (rc) 1532d2e75dffSTejun Heo goto out_restart; 1533d2e75dffSTejun Heo 1534d2e75dffSTejun Heo /* need to do CLO? */ 1535d2e75dffSTejun Heo if (!busy) { 1536d2e75dffSTejun Heo rc = 0; 1537d2e75dffSTejun Heo goto out_restart; 1538d2e75dffSTejun Heo } 1539d2e75dffSTejun Heo 1540d2e75dffSTejun Heo if (!(hpriv->cap & HOST_CAP_CLO)) { 1541d2e75dffSTejun Heo rc = -EOPNOTSUPP; 1542d2e75dffSTejun Heo goto out_restart; 1543d2e75dffSTejun Heo } 1544d2e75dffSTejun Heo 1545d2e75dffSTejun Heo /* perform CLO */ 1546c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 1547c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 1548c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 1549c6fd2807SJeff Garzik 1550d2e75dffSTejun Heo rc = 0; 1551c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 1552c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 1553c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 1554d2e75dffSTejun Heo rc = -EIO; 1555c6fd2807SJeff Garzik 1556d2e75dffSTejun Heo /* restart engine */ 1557d2e75dffSTejun Heo out_restart: 1558d2e75dffSTejun Heo ahci_start_engine(ap); 1559d2e75dffSTejun Heo return rc; 1560c6fd2807SJeff Garzik } 1561c6fd2807SJeff Garzik 156291c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, 156391c4a2e0STejun Heo struct ata_taskfile *tf, int is_cmd, u16 flags, 156491c4a2e0STejun Heo unsigned long timeout_msec) 156591c4a2e0STejun Heo { 156691c4a2e0STejun Heo const u32 cmd_fis_len = 5; /* five dwords */ 156791c4a2e0STejun Heo struct ahci_port_priv *pp = ap->private_data; 156891c4a2e0STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 156991c4a2e0STejun Heo u8 *fis = pp->cmd_tbl; 157091c4a2e0STejun Heo u32 tmp; 157191c4a2e0STejun Heo 157291c4a2e0STejun Heo /* prep the command */ 157391c4a2e0STejun Heo ata_tf_to_fis(tf, pmp, is_cmd, fis); 157491c4a2e0STejun Heo ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); 157591c4a2e0STejun Heo 157691c4a2e0STejun Heo /* issue & wait */ 157791c4a2e0STejun Heo writel(1, port_mmio + PORT_CMD_ISSUE); 157891c4a2e0STejun Heo 157991c4a2e0STejun Heo if (timeout_msec) { 158091c4a2e0STejun Heo tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 158191c4a2e0STejun Heo 1, timeout_msec); 158291c4a2e0STejun Heo if (tmp & 0x1) { 158391c4a2e0STejun Heo ahci_kick_engine(ap, 1); 158491c4a2e0STejun Heo return -EBUSY; 158591c4a2e0STejun Heo } 158691c4a2e0STejun Heo } else 158791c4a2e0STejun Heo readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 158891c4a2e0STejun Heo 158991c4a2e0STejun Heo return 0; 159091c4a2e0STejun Heo } 159191c4a2e0STejun Heo 1592bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class, 1593bd17243aSShane Huang int pmp, unsigned long deadline, 1594bd17243aSShane Huang int (*check_ready)(struct ata_link *link)) 1595c6fd2807SJeff Garzik { 1596cc0680a5STejun Heo struct ata_port *ap = link->ap; 1597c6fd2807SJeff Garzik const char *reason = NULL; 15982cbb79ebSTejun Heo unsigned long now, msecs; 1599c6fd2807SJeff Garzik struct ata_taskfile tf; 1600c6fd2807SJeff Garzik int rc; 1601c6fd2807SJeff Garzik 1602c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1603c6fd2807SJeff Garzik 1604c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 1605d2e75dffSTejun Heo rc = ahci_kick_engine(ap, 1); 1606994056d7STejun Heo if (rc && rc != -EOPNOTSUPP) 1607cc0680a5STejun Heo ata_link_printk(link, KERN_WARNING, 1608994056d7STejun Heo "failed to reset engine (errno=%d)\n", rc); 1609c6fd2807SJeff Garzik 1610cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1611c6fd2807SJeff Garzik 1612c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 16132cbb79ebSTejun Heo msecs = 0; 16142cbb79ebSTejun Heo now = jiffies; 16152cbb79ebSTejun Heo if (time_after(now, deadline)) 16162cbb79ebSTejun Heo msecs = jiffies_to_msecs(deadline - now); 16172cbb79ebSTejun Heo 1618c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 1619a9cf5e85STejun Heo if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, 162091c4a2e0STejun Heo AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { 1621c6fd2807SJeff Garzik rc = -EIO; 1622c6fd2807SJeff Garzik reason = "1st FIS failed"; 1623c6fd2807SJeff Garzik goto fail; 1624c6fd2807SJeff Garzik } 1625c6fd2807SJeff Garzik 1626c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 1627c6fd2807SJeff Garzik msleep(1); 1628c6fd2807SJeff Garzik 1629c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 1630c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 1631a9cf5e85STejun Heo ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1632c6fd2807SJeff Garzik 1633705e76beSTejun Heo /* wait for link to become ready */ 1634bd17243aSShane Huang rc = ata_wait_after_reset(link, deadline, check_ready); 16359b89391cSTejun Heo /* link occupied, -ENODEV too is an error */ 16369b89391cSTejun Heo if (rc) { 1637c6fd2807SJeff Garzik reason = "device not ready"; 1638c6fd2807SJeff Garzik goto fail; 1639c6fd2807SJeff Garzik } 1640c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1641c6fd2807SJeff Garzik 1642c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 1643c6fd2807SJeff Garzik return 0; 1644c6fd2807SJeff Garzik 1645c6fd2807SJeff Garzik fail: 1646cc0680a5STejun Heo ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); 1647c6fd2807SJeff Garzik return rc; 1648c6fd2807SJeff Garzik } 1649c6fd2807SJeff Garzik 1650bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link) 1651bd17243aSShane Huang { 1652bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(link->ap); 1653bd17243aSShane Huang u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1654bd17243aSShane Huang 1655bd17243aSShane Huang return ata_check_ready(status); 1656bd17243aSShane Huang } 1657bd17243aSShane Huang 1658bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class, 1659bd17243aSShane Huang unsigned long deadline) 1660bd17243aSShane Huang { 1661bd17243aSShane Huang int pmp = sata_srst_pmp(link); 1662bd17243aSShane Huang 1663bd17243aSShane Huang DPRINTK("ENTER\n"); 1664bd17243aSShane Huang 1665bd17243aSShane Huang return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); 1666bd17243aSShane Huang } 1667bd17243aSShane Huang 1668bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link) 1669bd17243aSShane Huang { 1670bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(link->ap); 1671bd17243aSShane Huang u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1672bd17243aSShane Huang u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); 1673bd17243aSShane Huang 1674bd17243aSShane Huang /* 1675bd17243aSShane Huang * There is no need to check TFDATA if BAD PMP is found due to HW bug, 1676bd17243aSShane Huang * which can save timeout delay. 1677bd17243aSShane Huang */ 1678bd17243aSShane Huang if (irq_status & PORT_IRQ_BAD_PMP) 1679bd17243aSShane Huang return -EIO; 1680bd17243aSShane Huang 1681bd17243aSShane Huang return ata_check_ready(status); 1682bd17243aSShane Huang } 1683bd17243aSShane Huang 1684bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, 1685bd17243aSShane Huang unsigned long deadline) 1686bd17243aSShane Huang { 1687bd17243aSShane Huang struct ata_port *ap = link->ap; 1688bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(ap); 1689bd17243aSShane Huang int pmp = sata_srst_pmp(link); 1690bd17243aSShane Huang int rc; 1691bd17243aSShane Huang u32 irq_sts; 1692bd17243aSShane Huang 1693bd17243aSShane Huang DPRINTK("ENTER\n"); 1694bd17243aSShane Huang 1695bd17243aSShane Huang rc = ahci_do_softreset(link, class, pmp, deadline, 1696bd17243aSShane Huang ahci_sb600_check_ready); 1697bd17243aSShane Huang 1698bd17243aSShane Huang /* 1699bd17243aSShane Huang * Soft reset fails on some ATI chips with IPMS set when PMP 1700bd17243aSShane Huang * is enabled but SATA HDD/ODD is connected to SATA port, 1701bd17243aSShane Huang * do soft reset again to port 0. 1702bd17243aSShane Huang */ 1703bd17243aSShane Huang if (rc == -EIO) { 1704bd17243aSShane Huang irq_sts = readl(port_mmio + PORT_IRQ_STAT); 1705bd17243aSShane Huang if (irq_sts & PORT_IRQ_BAD_PMP) { 1706bd17243aSShane Huang ata_link_printk(link, KERN_WARNING, 1707bd17243aSShane Huang "failed due to HW bug, retry pmp=0\n"); 1708bd17243aSShane Huang rc = ahci_do_softreset(link, class, 0, deadline, 1709bd17243aSShane Huang ahci_check_ready); 1710bd17243aSShane Huang } 1711bd17243aSShane Huang } 1712bd17243aSShane Huang 1713bd17243aSShane Huang return rc; 1714bd17243aSShane Huang } 1715bd17243aSShane Huang 1716cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1717d4b2bab4STejun Heo unsigned long deadline) 1718c6fd2807SJeff Garzik { 17199dadd45bSTejun Heo const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); 1720cc0680a5STejun Heo struct ata_port *ap = link->ap; 1721c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1722c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1723c6fd2807SJeff Garzik struct ata_taskfile tf; 17249dadd45bSTejun Heo bool online; 1725c6fd2807SJeff Garzik int rc; 1726c6fd2807SJeff Garzik 1727c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1728c6fd2807SJeff Garzik 17294447d351STejun Heo ahci_stop_engine(ap); 1730c6fd2807SJeff Garzik 1731c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1732cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1733dfd7a3dbSTejun Heo tf.command = 0x80; 17349977126cSTejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1735c6fd2807SJeff Garzik 17369dadd45bSTejun Heo rc = sata_link_hardreset(link, timing, deadline, &online, 17379dadd45bSTejun Heo ahci_check_ready); 1738c6fd2807SJeff Garzik 17394447d351STejun Heo ahci_start_engine(ap); 1740c6fd2807SJeff Garzik 17419dadd45bSTejun Heo if (online) 17429dadd45bSTejun Heo *class = ahci_dev_classify(ap); 1743c6fd2807SJeff Garzik 1744c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1745c6fd2807SJeff Garzik return rc; 1746c6fd2807SJeff Garzik } 1747c6fd2807SJeff Garzik 1748cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 1749d4b2bab4STejun Heo unsigned long deadline) 1750ad616ffbSTejun Heo { 1751cc0680a5STejun Heo struct ata_port *ap = link->ap; 17529dadd45bSTejun Heo bool online; 1753ad616ffbSTejun Heo int rc; 1754ad616ffbSTejun Heo 1755ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1756ad616ffbSTejun Heo 17574447d351STejun Heo ahci_stop_engine(ap); 1758ad616ffbSTejun Heo 1759cc0680a5STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 17609dadd45bSTejun Heo deadline, &online, NULL); 1761ad616ffbSTejun Heo 17624447d351STejun Heo ahci_start_engine(ap); 1763ad616ffbSTejun Heo 1764ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1765ad616ffbSTejun Heo 1766ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1767ad616ffbSTejun Heo * request follow-up softreset. 1768ad616ffbSTejun Heo */ 17699dadd45bSTejun Heo return online ? -EAGAIN : rc; 1770ad616ffbSTejun Heo } 1771ad616ffbSTejun Heo 1772edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 1773edc93052STejun Heo unsigned long deadline) 1774edc93052STejun Heo { 1775edc93052STejun Heo struct ata_port *ap = link->ap; 1776edc93052STejun Heo struct ahci_port_priv *pp = ap->private_data; 1777edc93052STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1778edc93052STejun Heo struct ata_taskfile tf; 17799dadd45bSTejun Heo bool online; 1780edc93052STejun Heo int rc; 1781edc93052STejun Heo 1782edc93052STejun Heo ahci_stop_engine(ap); 1783edc93052STejun Heo 1784edc93052STejun Heo /* clear D2H reception area to properly wait for D2H FIS */ 1785edc93052STejun Heo ata_tf_init(link->device, &tf); 1786edc93052STejun Heo tf.command = 0x80; 1787edc93052STejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1788edc93052STejun Heo 1789edc93052STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 17909dadd45bSTejun Heo deadline, &online, NULL); 1791edc93052STejun Heo 1792edc93052STejun Heo ahci_start_engine(ap); 1793edc93052STejun Heo 1794edc93052STejun Heo /* The pseudo configuration device on SIMG4726 attached to 1795edc93052STejun Heo * ASUS P5W-DH Deluxe doesn't send signature FIS after 1796edc93052STejun Heo * hardreset if no device is attached to the first downstream 1797edc93052STejun Heo * port && the pseudo device locks up on SRST w/ PMP==0. To 1798edc93052STejun Heo * work around this, wait for !BSY only briefly. If BSY isn't 1799edc93052STejun Heo * cleared, perform CLO and proceed to IDENTIFY (achieved by 1800edc93052STejun Heo * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA). 1801edc93052STejun Heo * 1802edc93052STejun Heo * Wait for two seconds. Devices attached to downstream port 1803edc93052STejun Heo * which can't process the following IDENTIFY after this will 1804edc93052STejun Heo * have to be reset again. For most cases, this should 1805edc93052STejun Heo * suffice while making probing snappish enough. 1806edc93052STejun Heo */ 18079dadd45bSTejun Heo if (online) { 18089dadd45bSTejun Heo rc = ata_wait_after_reset(link, jiffies + 2 * HZ, 18099dadd45bSTejun Heo ahci_check_ready); 1810edc93052STejun Heo if (rc) 1811edc93052STejun Heo ahci_kick_engine(ap, 0); 18129dadd45bSTejun Heo } 18139dadd45bSTejun Heo return rc; 1814edc93052STejun Heo } 1815edc93052STejun Heo 1816cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class) 1817c6fd2807SJeff Garzik { 1818cc0680a5STejun Heo struct ata_port *ap = link->ap; 18194447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1820c6fd2807SJeff Garzik u32 new_tmp, tmp; 1821c6fd2807SJeff Garzik 1822203c75b8STejun Heo ata_std_postreset(link, class); 1823c6fd2807SJeff Garzik 1824c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1825c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1826c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1827c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1828c6fd2807SJeff Garzik else 1829c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1830c6fd2807SJeff Garzik if (new_tmp != tmp) { 1831c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1832c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1833c6fd2807SJeff Garzik } 1834c6fd2807SJeff Garzik } 1835c6fd2807SJeff Garzik 1836c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1837c6fd2807SJeff Garzik { 1838c6fd2807SJeff Garzik struct scatterlist *sg; 1839ff2aeb1eSTejun Heo struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1840ff2aeb1eSTejun Heo unsigned int si; 1841c6fd2807SJeff Garzik 1842c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1843c6fd2807SJeff Garzik 1844c6fd2807SJeff Garzik /* 1845c6fd2807SJeff Garzik * Next, the S/G list. 1846c6fd2807SJeff Garzik */ 1847ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) { 1848c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1849c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1850c6fd2807SJeff Garzik 1851ff2aeb1eSTejun Heo ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); 1852ff2aeb1eSTejun Heo ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); 1853ff2aeb1eSTejun Heo ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); 1854c6fd2807SJeff Garzik } 1855c6fd2807SJeff Garzik 1856ff2aeb1eSTejun Heo return si; 1857c6fd2807SJeff Garzik } 1858c6fd2807SJeff Garzik 1859c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1860c6fd2807SJeff Garzik { 1861c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1862c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1863405e66b3STejun Heo int is_atapi = ata_is_atapi(qc->tf.protocol); 1864c6fd2807SJeff Garzik void *cmd_tbl; 1865c6fd2807SJeff Garzik u32 opts; 1866c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1867c6fd2807SJeff Garzik unsigned int n_elem; 1868c6fd2807SJeff Garzik 1869c6fd2807SJeff Garzik /* 1870c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1871c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1872c6fd2807SJeff Garzik */ 1873c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1874c6fd2807SJeff Garzik 18757d50b60bSTejun Heo ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); 1876c6fd2807SJeff Garzik if (is_atapi) { 1877c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1878c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1879c6fd2807SJeff Garzik } 1880c6fd2807SJeff Garzik 1881c6fd2807SJeff Garzik n_elem = 0; 1882c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1883c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1884c6fd2807SJeff Garzik 1885c6fd2807SJeff Garzik /* 1886c6fd2807SJeff Garzik * Fill in command slot information. 1887c6fd2807SJeff Garzik */ 18887d50b60bSTejun Heo opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); 1889c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1890c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1891c6fd2807SJeff Garzik if (is_atapi) 1892c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1893c6fd2807SJeff Garzik 1894c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1895c6fd2807SJeff Garzik } 1896c6fd2807SJeff Garzik 1897c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1898c6fd2807SJeff Garzik { 1899417a1a6dSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1900c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 19017d50b60bSTejun Heo struct ata_eh_info *host_ehi = &ap->link.eh_info; 19027d50b60bSTejun Heo struct ata_link *link = NULL; 19037d50b60bSTejun Heo struct ata_queued_cmd *active_qc; 19047d50b60bSTejun Heo struct ata_eh_info *active_ehi; 1905c6fd2807SJeff Garzik u32 serror; 1906c6fd2807SJeff Garzik 19077d50b60bSTejun Heo /* determine active link */ 19087d50b60bSTejun Heo ata_port_for_each_link(link, ap) 19097d50b60bSTejun Heo if (ata_link_active(link)) 19107d50b60bSTejun Heo break; 19117d50b60bSTejun Heo if (!link) 19127d50b60bSTejun Heo link = &ap->link; 19137d50b60bSTejun Heo 19147d50b60bSTejun Heo active_qc = ata_qc_from_tag(ap, link->active_tag); 19157d50b60bSTejun Heo active_ehi = &link->eh_info; 19167d50b60bSTejun Heo 19177d50b60bSTejun Heo /* record irq stat */ 19187d50b60bSTejun Heo ata_ehi_clear_desc(host_ehi); 19197d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); 1920c6fd2807SJeff Garzik 1921c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 1922da3dbb17STejun Heo ahci_scr_read(ap, SCR_ERROR, &serror); 1923c6fd2807SJeff Garzik ahci_scr_write(ap, SCR_ERROR, serror); 19247d50b60bSTejun Heo host_ehi->serror |= serror; 1925c6fd2807SJeff Garzik 192641669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 1927417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) 192841669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 192941669553STejun Heo 193055a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 19317d50b60bSTejun Heo /* If qc is active, charge it; otherwise, the active 19327d50b60bSTejun Heo * link. There's no active qc on NCQ errors. It will 19337d50b60bSTejun Heo * be determined by EH by reading log page 10h. 19347d50b60bSTejun Heo */ 19357d50b60bSTejun Heo if (active_qc) 19367d50b60bSTejun Heo active_qc->err_mask |= AC_ERR_DEV; 19377d50b60bSTejun Heo else 19387d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_DEV; 19397d50b60bSTejun Heo 1940417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) 19417d50b60bSTejun Heo host_ehi->serror &= ~SERR_INTERNAL; 1942c6fd2807SJeff Garzik } 1943c6fd2807SJeff Garzik 1944c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1945c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1946c6fd2807SJeff Garzik 19477d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1948cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 19497d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, 19507d50b60bSTejun Heo "unknown FIS %08x %08x %08x %08x" , 1951c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1952c6fd2807SJeff Garzik } 1953c6fd2807SJeff Garzik 1954071f44b1STejun Heo if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) { 19557d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1956cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 19577d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, "incorrect PMP"); 19587d50b60bSTejun Heo } 1959c6fd2807SJeff Garzik 19607d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 19617d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_HOST_BUS; 1962cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 19637d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "host bus error"); 19647d50b60bSTejun Heo } 19657d50b60bSTejun Heo 19667d50b60bSTejun Heo if (irq_stat & PORT_IRQ_IF_ERR) { 19677d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_ATA_BUS; 1968cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 19697d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "interface fatal error"); 19707d50b60bSTejun Heo } 19717d50b60bSTejun Heo 19727d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 19737d50b60bSTejun Heo ata_ehi_hotplugged(host_ehi); 19747d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "%s", 19757d50b60bSTejun Heo irq_stat & PORT_IRQ_CONNECT ? 19767d50b60bSTejun Heo "connection status changed" : "PHY RDY changed"); 19777d50b60bSTejun Heo } 19787d50b60bSTejun Heo 19797d50b60bSTejun Heo /* okay, let's hand over to EH */ 1980c6fd2807SJeff Garzik 1981c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 1982c6fd2807SJeff Garzik ata_port_freeze(ap); 1983c6fd2807SJeff Garzik else 1984c6fd2807SJeff Garzik ata_port_abort(ap); 1985c6fd2807SJeff Garzik } 1986c6fd2807SJeff Garzik 1987df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap) 1988c6fd2807SJeff Garzik { 1989350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 19909af5c9c9STejun Heo struct ata_eh_info *ehi = &ap->link.eh_info; 19910291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 19925f226c6bSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1993b06ce3e5STejun Heo int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 1994c6fd2807SJeff Garzik u32 status, qc_active; 1995459ad688STejun Heo int rc; 1996c6fd2807SJeff Garzik 1997c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 1998c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 1999c6fd2807SJeff Garzik 2000b06ce3e5STejun Heo /* ignore BAD_PMP while resetting */ 2001b06ce3e5STejun Heo if (unlikely(resetting)) 2002b06ce3e5STejun Heo status &= ~PORT_IRQ_BAD_PMP; 2003b06ce3e5STejun Heo 200431556594SKristen Carlson Accardi /* If we are getting PhyRdy, this is 200531556594SKristen Carlson Accardi * just a power state change, we should 200631556594SKristen Carlson Accardi * clear out this, plus the PhyRdy/Comm 200731556594SKristen Carlson Accardi * Wake bits from Serror 200831556594SKristen Carlson Accardi */ 200931556594SKristen Carlson Accardi if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && 201031556594SKristen Carlson Accardi (status & PORT_IRQ_PHYRDY)) { 201131556594SKristen Carlson Accardi status &= ~PORT_IRQ_PHYRDY; 201231556594SKristen Carlson Accardi ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); 201331556594SKristen Carlson Accardi } 201431556594SKristen Carlson Accardi 2015c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 2016c6fd2807SJeff Garzik ahci_error_intr(ap, status); 2017c6fd2807SJeff Garzik return; 2018c6fd2807SJeff Garzik } 2019c6fd2807SJeff Garzik 20202f294968SKristen Carlson Accardi if (status & PORT_IRQ_SDB_FIS) { 20215f226c6bSTejun Heo /* If SNotification is available, leave notification 20225f226c6bSTejun Heo * handling to sata_async_notification(). If not, 20235f226c6bSTejun Heo * emulate it by snooping SDB FIS RX area. 20245f226c6bSTejun Heo * 20255f226c6bSTejun Heo * Snooping FIS RX area is probably cheaper than 20265f226c6bSTejun Heo * poking SNotification but some constrollers which 20275f226c6bSTejun Heo * implement SNotification, ICH9 for example, don't 20285f226c6bSTejun Heo * store AN SDB FIS into receive area. 20295f226c6bSTejun Heo */ 20305f226c6bSTejun Heo if (hpriv->cap & HOST_CAP_SNTF) 20315f226c6bSTejun Heo sata_async_notification(ap); 20325f226c6bSTejun Heo else { 20335f226c6bSTejun Heo /* If the 'N' bit in word 0 of the FIS is set, 20345f226c6bSTejun Heo * we just received asynchronous notification. 20355f226c6bSTejun Heo * Tell libata about it. 20362f294968SKristen Carlson Accardi */ 20372f294968SKristen Carlson Accardi const __le32 *f = pp->rx_fis + RX_FIS_SDB; 20382f294968SKristen Carlson Accardi u32 f0 = le32_to_cpu(f[0]); 20392f294968SKristen Carlson Accardi 20407d77b247STejun Heo if (f0 & (1 << 15)) 20417d77b247STejun Heo sata_async_notification(ap); 20422f294968SKristen Carlson Accardi } 20435f226c6bSTejun Heo } 20442f294968SKristen Carlson Accardi 20457d50b60bSTejun Heo /* pp->active_link is valid iff any command is in flight */ 20467d50b60bSTejun Heo if (ap->qc_active && pp->active_link->sactive) 2047c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 2048c6fd2807SJeff Garzik else 2049c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 2050c6fd2807SJeff Garzik 205179f97dadSTejun Heo rc = ata_qc_complete_multiple(ap, qc_active); 2052b06ce3e5STejun Heo 2053459ad688STejun Heo /* while resetting, invalid completions are expected */ 2054459ad688STejun Heo if (unlikely(rc < 0 && !resetting)) { 2055c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 2056cf480626STejun Heo ehi->action |= ATA_EH_RESET; 2057c6fd2807SJeff Garzik ata_port_freeze(ap); 2058c6fd2807SJeff Garzik } 2059c6fd2807SJeff Garzik } 2060c6fd2807SJeff Garzik 20617d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 2062c6fd2807SJeff Garzik { 2063cca3974eSJeff Garzik struct ata_host *host = dev_instance; 2064c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 2065c6fd2807SJeff Garzik unsigned int i, handled = 0; 2066c6fd2807SJeff Garzik void __iomem *mmio; 2067d28f87aaSTejun Heo u32 irq_stat, irq_masked; 2068c6fd2807SJeff Garzik 2069c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2070c6fd2807SJeff Garzik 2071cca3974eSJeff Garzik hpriv = host->private_data; 20720d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 2073c6fd2807SJeff Garzik 2074c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 2075c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 2076c6fd2807SJeff Garzik if (!irq_stat) 2077c6fd2807SJeff Garzik return IRQ_NONE; 2078c6fd2807SJeff Garzik 2079d28f87aaSTejun Heo irq_masked = irq_stat & hpriv->port_map; 2080d28f87aaSTejun Heo 2081cca3974eSJeff Garzik spin_lock(&host->lock); 2082c6fd2807SJeff Garzik 2083cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 2084c6fd2807SJeff Garzik struct ata_port *ap; 2085c6fd2807SJeff Garzik 2086d28f87aaSTejun Heo if (!(irq_masked & (1 << i))) 2087c6fd2807SJeff Garzik continue; 2088c6fd2807SJeff Garzik 2089cca3974eSJeff Garzik ap = host->ports[i]; 2090c6fd2807SJeff Garzik if (ap) { 2091df69c9c5SJeff Garzik ahci_port_intr(ap); 2092c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 2093c6fd2807SJeff Garzik } else { 2094c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 2095c6fd2807SJeff Garzik if (ata_ratelimit()) 2096cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 2097c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 2098c6fd2807SJeff Garzik } 2099c6fd2807SJeff Garzik 2100c6fd2807SJeff Garzik handled = 1; 2101c6fd2807SJeff Garzik } 2102c6fd2807SJeff Garzik 2103d28f87aaSTejun Heo /* HOST_IRQ_STAT behaves as level triggered latch meaning that 2104d28f87aaSTejun Heo * it should be cleared after all the port events are cleared; 2105d28f87aaSTejun Heo * otherwise, it will raise a spurious interrupt after each 2106d28f87aaSTejun Heo * valid one. Please read section 10.6.2 of ahci 1.1 for more 2107d28f87aaSTejun Heo * information. 2108d28f87aaSTejun Heo * 2109d28f87aaSTejun Heo * Also, use the unmasked value to clear interrupt as spurious 2110d28f87aaSTejun Heo * pending event on a dummy port might cause screaming IRQ. 2111d28f87aaSTejun Heo */ 2112ea0c62f7STejun Heo writel(irq_stat, mmio + HOST_IRQ_STAT); 2113ea0c62f7STejun Heo 2114cca3974eSJeff Garzik spin_unlock(&host->lock); 2115c6fd2807SJeff Garzik 2116c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 2117c6fd2807SJeff Garzik 2118c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 2119c6fd2807SJeff Garzik } 2120c6fd2807SJeff Garzik 2121c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 2122c6fd2807SJeff Garzik { 2123c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 21244447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 21257d50b60bSTejun Heo struct ahci_port_priv *pp = ap->private_data; 21267d50b60bSTejun Heo 21277d50b60bSTejun Heo /* Keep track of the currently active link. It will be used 21287d50b60bSTejun Heo * in completion path to determine whether NCQ phase is in 21297d50b60bSTejun Heo * progress. 21307d50b60bSTejun Heo */ 21317d50b60bSTejun Heo pp->active_link = qc->dev->link; 2132c6fd2807SJeff Garzik 2133c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 2134c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 2135c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 2136c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 2137c6fd2807SJeff Garzik 2138*18f7ba4cSKristen Carlson Accardi ahci_sw_activity(qc->dev->link); 2139*18f7ba4cSKristen Carlson Accardi 2140c6fd2807SJeff Garzik return 0; 2141c6fd2807SJeff Garzik } 2142c6fd2807SJeff Garzik 21434c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) 21444c9bf4e7STejun Heo { 21454c9bf4e7STejun Heo struct ahci_port_priv *pp = qc->ap->private_data; 21464c9bf4e7STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 21474c9bf4e7STejun Heo 21484c9bf4e7STejun Heo ata_tf_from_fis(d2h_fis, &qc->result_tf); 21494c9bf4e7STejun Heo return true; 21504c9bf4e7STejun Heo } 21514c9bf4e7STejun Heo 2152c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 2153c6fd2807SJeff Garzik { 21544447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 2155c6fd2807SJeff Garzik 2156c6fd2807SJeff Garzik /* turn IRQ off */ 2157c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 2158c6fd2807SJeff Garzik } 2159c6fd2807SJeff Garzik 2160c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 2161c6fd2807SJeff Garzik { 21620d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 21634447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 2164c6fd2807SJeff Garzik u32 tmp; 2165a7384925SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 2166c6fd2807SJeff Garzik 2167c6fd2807SJeff Garzik /* clear IRQ */ 2168c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 2169c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 2170a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 2171c6fd2807SJeff Garzik 21721c954a4dSTejun Heo /* turn IRQ back on */ 21731c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 2174c6fd2807SJeff Garzik } 2175c6fd2807SJeff Garzik 2176c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 2177c6fd2807SJeff Garzik { 2178c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 2179c6fd2807SJeff Garzik /* restart engine */ 21804447d351STejun Heo ahci_stop_engine(ap); 21814447d351STejun Heo ahci_start_engine(ap); 2182c6fd2807SJeff Garzik } 2183c6fd2807SJeff Garzik 2184a1efdabaSTejun Heo sata_pmp_error_handler(ap); 2185edc93052STejun Heo } 2186edc93052STejun Heo 2187c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 2188c6fd2807SJeff Garzik { 2189c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 2190c6fd2807SJeff Garzik 2191c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 2192d2e75dffSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) 2193d2e75dffSTejun Heo ahci_kick_engine(ap, 1); 2194c6fd2807SJeff Garzik } 2195c6fd2807SJeff Garzik 21967d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap) 21977d50b60bSTejun Heo { 21987d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 21991c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 22007d50b60bSTejun Heo u32 cmd; 22017d50b60bSTejun Heo 22027d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 22037d50b60bSTejun Heo cmd |= PORT_CMD_PMP; 22047d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 22051c954a4dSTejun Heo 22061c954a4dSTejun Heo pp->intr_mask |= PORT_IRQ_BAD_PMP; 22071c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 22087d50b60bSTejun Heo } 22097d50b60bSTejun Heo 22107d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap) 22117d50b60bSTejun Heo { 22127d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 22131c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 22147d50b60bSTejun Heo u32 cmd; 22157d50b60bSTejun Heo 22167d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 22177d50b60bSTejun Heo cmd &= ~PORT_CMD_PMP; 22187d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 22191c954a4dSTejun Heo 22201c954a4dSTejun Heo pp->intr_mask &= ~PORT_IRQ_BAD_PMP; 22211c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 22227d50b60bSTejun Heo } 22237d50b60bSTejun Heo 2224028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap) 2225028a2596SAlexey Dobriyan { 2226028a2596SAlexey Dobriyan ahci_power_up(ap); 2227028a2596SAlexey Dobriyan ahci_start_port(ap); 2228028a2596SAlexey Dobriyan 2229071f44b1STejun Heo if (sata_pmp_attached(ap)) 22307d50b60bSTejun Heo ahci_pmp_attach(ap); 22317d50b60bSTejun Heo else 22327d50b60bSTejun Heo ahci_pmp_detach(ap); 22337d50b60bSTejun Heo 2234028a2596SAlexey Dobriyan return 0; 2235028a2596SAlexey Dobriyan } 2236028a2596SAlexey Dobriyan 2237438ac6d5STejun Heo #ifdef CONFIG_PM 2238c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 2239c6fd2807SJeff Garzik { 2240c6fd2807SJeff Garzik const char *emsg = NULL; 2241c6fd2807SJeff Garzik int rc; 2242c6fd2807SJeff Garzik 22434447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 22448e16f941STejun Heo if (rc == 0) 22454447d351STejun Heo ahci_power_down(ap); 22468e16f941STejun Heo else { 2247c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 2248df69c9c5SJeff Garzik ahci_start_port(ap); 2249c6fd2807SJeff Garzik } 2250c6fd2807SJeff Garzik 2251c6fd2807SJeff Garzik return rc; 2252c6fd2807SJeff Garzik } 2253c6fd2807SJeff Garzik 2254c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 2255c6fd2807SJeff Garzik { 2256cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 22570d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2258c6fd2807SJeff Garzik u32 ctl; 2259c6fd2807SJeff Garzik 22603a2d5b70SRafael J. Wysocki if (mesg.event & PM_EVENT_SLEEP) { 2261c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 2262c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 2263c6fd2807SJeff Garzik * transition of the HBA to D3 state. 2264c6fd2807SJeff Garzik */ 2265c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 2266c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 2267c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 2268c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 2269c6fd2807SJeff Garzik } 2270c6fd2807SJeff Garzik 2271c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 2272c6fd2807SJeff Garzik } 2273c6fd2807SJeff Garzik 2274c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 2275c6fd2807SJeff Garzik { 2276cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 2277c6fd2807SJeff Garzik int rc; 2278c6fd2807SJeff Garzik 2279553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 2280553c4aa6STejun Heo if (rc) 2281553c4aa6STejun Heo return rc; 2282c6fd2807SJeff Garzik 2283c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 22844447d351STejun Heo rc = ahci_reset_controller(host); 2285c6fd2807SJeff Garzik if (rc) 2286c6fd2807SJeff Garzik return rc; 2287c6fd2807SJeff Garzik 22884447d351STejun Heo ahci_init_controller(host); 2289c6fd2807SJeff Garzik } 2290c6fd2807SJeff Garzik 2291cca3974eSJeff Garzik ata_host_resume(host); 2292c6fd2807SJeff Garzik 2293c6fd2807SJeff Garzik return 0; 2294c6fd2807SJeff Garzik } 2295438ac6d5STejun Heo #endif 2296c6fd2807SJeff Garzik 2297c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 2298c6fd2807SJeff Garzik { 2299cca3974eSJeff Garzik struct device *dev = ap->host->dev; 2300c6fd2807SJeff Garzik struct ahci_port_priv *pp; 2301c6fd2807SJeff Garzik void *mem; 2302c6fd2807SJeff Garzik dma_addr_t mem_dma; 2303c6fd2807SJeff Garzik 230424dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 2305c6fd2807SJeff Garzik if (!pp) 2306c6fd2807SJeff Garzik return -ENOMEM; 2307c6fd2807SJeff Garzik 230824dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 230924dc5f33STejun Heo GFP_KERNEL); 231024dc5f33STejun Heo if (!mem) 2311c6fd2807SJeff Garzik return -ENOMEM; 2312c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 2313c6fd2807SJeff Garzik 2314c6fd2807SJeff Garzik /* 2315c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 2316c6fd2807SJeff Garzik * 32 bytes each in size 2317c6fd2807SJeff Garzik */ 2318c6fd2807SJeff Garzik pp->cmd_slot = mem; 2319c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 2320c6fd2807SJeff Garzik 2321c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 2322c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 2323c6fd2807SJeff Garzik 2324c6fd2807SJeff Garzik /* 2325c6fd2807SJeff Garzik * Second item: Received-FIS area 2326c6fd2807SJeff Garzik */ 2327c6fd2807SJeff Garzik pp->rx_fis = mem; 2328c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 2329c6fd2807SJeff Garzik 2330c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 2331c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 2332c6fd2807SJeff Garzik 2333c6fd2807SJeff Garzik /* 2334c6fd2807SJeff Garzik * Third item: data area for storing a single command 2335c6fd2807SJeff Garzik * and its scatter-gather table 2336c6fd2807SJeff Garzik */ 2337c6fd2807SJeff Garzik pp->cmd_tbl = mem; 2338c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 2339c6fd2807SJeff Garzik 2340a7384925SKristen Carlson Accardi /* 2341a7384925SKristen Carlson Accardi * Save off initial list of interrupts to be enabled. 2342a7384925SKristen Carlson Accardi * This could be changed later 2343a7384925SKristen Carlson Accardi */ 2344a7384925SKristen Carlson Accardi pp->intr_mask = DEF_PORT_IRQ; 2345a7384925SKristen Carlson Accardi 2346c6fd2807SJeff Garzik ap->private_data = pp; 2347c6fd2807SJeff Garzik 2348df69c9c5SJeff Garzik /* engage engines, captain */ 2349df69c9c5SJeff Garzik return ahci_port_resume(ap); 2350c6fd2807SJeff Garzik } 2351c6fd2807SJeff Garzik 2352c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 2353c6fd2807SJeff Garzik { 2354c6fd2807SJeff Garzik const char *emsg = NULL; 2355c6fd2807SJeff Garzik int rc; 2356c6fd2807SJeff Garzik 2357c6fd2807SJeff Garzik /* de-initialize port */ 23584447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 2359c6fd2807SJeff Garzik if (rc) 2360c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 2361c6fd2807SJeff Garzik } 2362c6fd2807SJeff Garzik 23634447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 2364c6fd2807SJeff Garzik { 2365c6fd2807SJeff Garzik int rc; 2366c6fd2807SJeff Garzik 2367c6fd2807SJeff Garzik if (using_dac && 2368c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 2369c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 2370c6fd2807SJeff Garzik if (rc) { 2371c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2372c6fd2807SJeff Garzik if (rc) { 2373c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2374c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 2375c6fd2807SJeff Garzik return rc; 2376c6fd2807SJeff Garzik } 2377c6fd2807SJeff Garzik } 2378c6fd2807SJeff Garzik } else { 2379c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 2380c6fd2807SJeff Garzik if (rc) { 2381c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2382c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 2383c6fd2807SJeff Garzik return rc; 2384c6fd2807SJeff Garzik } 2385c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2386c6fd2807SJeff Garzik if (rc) { 2387c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2388c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 2389c6fd2807SJeff Garzik return rc; 2390c6fd2807SJeff Garzik } 2391c6fd2807SJeff Garzik } 2392c6fd2807SJeff Garzik return 0; 2393c6fd2807SJeff Garzik } 2394c6fd2807SJeff Garzik 23954447d351STejun Heo static void ahci_print_info(struct ata_host *host) 2396c6fd2807SJeff Garzik { 23974447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 23984447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 23994447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2400c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 2401c6fd2807SJeff Garzik const char *speed_s; 2402c6fd2807SJeff Garzik u16 cc; 2403c6fd2807SJeff Garzik const char *scc_s; 2404c6fd2807SJeff Garzik 2405c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 2406c6fd2807SJeff Garzik cap = hpriv->cap; 2407c6fd2807SJeff Garzik impl = hpriv->port_map; 2408c6fd2807SJeff Garzik 2409c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 2410c6fd2807SJeff Garzik if (speed == 1) 2411c6fd2807SJeff Garzik speed_s = "1.5"; 2412c6fd2807SJeff Garzik else if (speed == 2) 2413c6fd2807SJeff Garzik speed_s = "3"; 2414c6fd2807SJeff Garzik else 2415c6fd2807SJeff Garzik speed_s = "?"; 2416c6fd2807SJeff Garzik 2417c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 2418c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 2419c6fd2807SJeff Garzik scc_s = "IDE"; 2420c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 2421c6fd2807SJeff Garzik scc_s = "SATA"; 2422c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 2423c6fd2807SJeff Garzik scc_s = "RAID"; 2424c6fd2807SJeff Garzik else 2425c6fd2807SJeff Garzik scc_s = "unknown"; 2426c6fd2807SJeff Garzik 2427c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2428c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 2429c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 2430c6fd2807SJeff Garzik , 2431c6fd2807SJeff Garzik 2432c6fd2807SJeff Garzik (vers >> 24) & 0xff, 2433c6fd2807SJeff Garzik (vers >> 16) & 0xff, 2434c6fd2807SJeff Garzik (vers >> 8) & 0xff, 2435c6fd2807SJeff Garzik vers & 0xff, 2436c6fd2807SJeff Garzik 2437c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 2438c6fd2807SJeff Garzik (cap & 0x1f) + 1, 2439c6fd2807SJeff Garzik speed_s, 2440c6fd2807SJeff Garzik impl, 2441c6fd2807SJeff Garzik scc_s); 2442c6fd2807SJeff Garzik 2443c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2444c6fd2807SJeff Garzik "flags: " 2445203ef6c4STejun Heo "%s%s%s%s%s%s%s" 2446*18f7ba4cSKristen Carlson Accardi "%s%s%s%s%s%s%s" 2447*18f7ba4cSKristen Carlson Accardi "%s\n" 2448c6fd2807SJeff Garzik , 2449c6fd2807SJeff Garzik 2450c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 2451c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 2452203ef6c4STejun Heo cap & (1 << 29) ? "sntf " : "", 2453c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 2454c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 2455c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 2456c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 2457c6fd2807SJeff Garzik 2458c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 2459c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 2460c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 2461c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 2462c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 2463c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 2464*18f7ba4cSKristen Carlson Accardi cap & (1 << 13) ? "part " : "", 2465*18f7ba4cSKristen Carlson Accardi cap & (1 << 6) ? "ems ": "" 2466c6fd2807SJeff Garzik ); 2467c6fd2807SJeff Garzik } 2468c6fd2807SJeff Garzik 2469edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is 2470edc93052STejun Heo * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't 2471edc93052STejun Heo * support PMP and the 4726 either directly exports the device 2472edc93052STejun Heo * attached to the first downstream port or acts as a hardware storage 2473edc93052STejun Heo * controller and emulate a single ATA device (can be RAID 0/1 or some 2474edc93052STejun Heo * other configuration). 2475edc93052STejun Heo * 2476edc93052STejun Heo * When there's no device attached to the first downstream port of the 2477edc93052STejun Heo * 4726, "Config Disk" appears, which is a pseudo ATA device to 2478edc93052STejun Heo * configure the 4726. However, ATA emulation of the device is very 2479edc93052STejun Heo * lame. It doesn't send signature D2H Reg FIS after the initial 2480edc93052STejun Heo * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. 2481edc93052STejun Heo * 2482edc93052STejun Heo * The following function works around the problem by always using 2483edc93052STejun Heo * hardreset on the port and not depending on receiving signature FIS 2484edc93052STejun Heo * afterward. If signature FIS isn't received soon, ATA class is 2485edc93052STejun Heo * assumed without follow-up softreset. 2486edc93052STejun Heo */ 2487edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host) 2488edc93052STejun Heo { 2489edc93052STejun Heo static struct dmi_system_id sysids[] = { 2490edc93052STejun Heo { 2491edc93052STejun Heo .ident = "P5W DH Deluxe", 2492edc93052STejun Heo .matches = { 2493edc93052STejun Heo DMI_MATCH(DMI_SYS_VENDOR, 2494edc93052STejun Heo "ASUSTEK COMPUTER INC"), 2495edc93052STejun Heo DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), 2496edc93052STejun Heo }, 2497edc93052STejun Heo }, 2498edc93052STejun Heo { } 2499edc93052STejun Heo }; 2500edc93052STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 2501edc93052STejun Heo 2502edc93052STejun Heo if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) && 2503edc93052STejun Heo dmi_check_system(sysids)) { 2504edc93052STejun Heo struct ata_port *ap = host->ports[1]; 2505edc93052STejun Heo 2506edc93052STejun Heo dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " 2507edc93052STejun Heo "Deluxe on-board SIMG4726 workaround\n"); 2508edc93052STejun Heo 2509edc93052STejun Heo ap->ops = &ahci_p5wdh_ops; 2510edc93052STejun Heo ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; 2511edc93052STejun Heo } 2512edc93052STejun Heo } 2513edc93052STejun Heo 2514c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2515c6fd2807SJeff Garzik { 2516c6fd2807SJeff Garzik static int printed_version; 2517e297d99eSTejun Heo unsigned int board_id = ent->driver_data; 2518e297d99eSTejun Heo struct ata_port_info pi = ahci_port_info[board_id]; 25194447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 252024dc5f33STejun Heo struct device *dev = &pdev->dev; 2521c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 25224447d351STejun Heo struct ata_host *host; 2523837f5f8fSTejun Heo int n_ports, i, rc; 2524c6fd2807SJeff Garzik 2525c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2526c6fd2807SJeff Garzik 2527c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 2528c6fd2807SJeff Garzik 2529c6fd2807SJeff Garzik if (!printed_version++) 2530c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 2531c6fd2807SJeff Garzik 25324447d351STejun Heo /* acquire resources */ 253324dc5f33STejun Heo rc = pcim_enable_device(pdev); 2534c6fd2807SJeff Garzik if (rc) 2535c6fd2807SJeff Garzik return rc; 2536c6fd2807SJeff Garzik 2537dea55137STejun Heo /* AHCI controllers often implement SFF compatible interface. 2538dea55137STejun Heo * Grab all PCI BARs just in case. 2539dea55137STejun Heo */ 2540dea55137STejun Heo rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 25410d5ff566STejun Heo if (rc == -EBUSY) 254224dc5f33STejun Heo pcim_pin_device(pdev); 25430d5ff566STejun Heo if (rc) 254424dc5f33STejun Heo return rc; 2545c6fd2807SJeff Garzik 2546c4f7792cSTejun Heo if (pdev->vendor == PCI_VENDOR_ID_INTEL && 2547c4f7792cSTejun Heo (pdev->device == 0x2652 || pdev->device == 0x2653)) { 2548c4f7792cSTejun Heo u8 map; 2549c4f7792cSTejun Heo 2550c4f7792cSTejun Heo /* ICH6s share the same PCI ID for both piix and ahci 2551c4f7792cSTejun Heo * modes. Enabling ahci mode while MAP indicates 2552c4f7792cSTejun Heo * combined mode is a bad idea. Yield to ata_piix. 2553c4f7792cSTejun Heo */ 2554c4f7792cSTejun Heo pci_read_config_byte(pdev, ICH_MAP, &map); 2555c4f7792cSTejun Heo if (map & 0x3) { 2556c4f7792cSTejun Heo dev_printk(KERN_INFO, &pdev->dev, "controller is in " 2557c4f7792cSTejun Heo "combined mode, can't enable AHCI mode\n"); 2558c4f7792cSTejun Heo return -ENODEV; 2559c4f7792cSTejun Heo } 2560c4f7792cSTejun Heo } 2561c4f7792cSTejun Heo 256224dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 256324dc5f33STejun Heo if (!hpriv) 256424dc5f33STejun Heo return -ENOMEM; 2565417a1a6dSTejun Heo hpriv->flags |= (unsigned long)pi.private_data; 2566417a1a6dSTejun Heo 2567e297d99eSTejun Heo /* MCP65 revision A1 and A2 can't do MSI */ 2568e297d99eSTejun Heo if (board_id == board_ahci_mcp65 && 2569e297d99eSTejun Heo (pdev->revision == 0xa1 || pdev->revision == 0xa2)) 2570e297d99eSTejun Heo hpriv->flags |= AHCI_HFLAG_NO_MSI; 2571e297d99eSTejun Heo 2572417a1a6dSTejun Heo if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) 2573417a1a6dSTejun Heo pci_intx(pdev, 1); 2574c6fd2807SJeff Garzik 25754447d351STejun Heo /* save initial config */ 2576417a1a6dSTejun Heo ahci_save_initial_config(pdev, hpriv); 2577c6fd2807SJeff Garzik 25784447d351STejun Heo /* prepare host */ 2579274c1fdeSTejun Heo if (hpriv->cap & HOST_CAP_NCQ) 25804447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 25814447d351STejun Heo 25827d50b60bSTejun Heo if (hpriv->cap & HOST_CAP_PMP) 25837d50b60bSTejun Heo pi.flags |= ATA_FLAG_PMP; 25847d50b60bSTejun Heo 2585*18f7ba4cSKristen Carlson Accardi if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) { 2586*18f7ba4cSKristen Carlson Accardi u8 messages; 2587*18f7ba4cSKristen Carlson Accardi void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 2588*18f7ba4cSKristen Carlson Accardi u32 em_loc = readl(mmio + HOST_EM_LOC); 2589*18f7ba4cSKristen Carlson Accardi u32 em_ctl = readl(mmio + HOST_EM_CTL); 2590*18f7ba4cSKristen Carlson Accardi 2591*18f7ba4cSKristen Carlson Accardi messages = (em_ctl & 0x000f0000) >> 16; 2592*18f7ba4cSKristen Carlson Accardi 2593*18f7ba4cSKristen Carlson Accardi /* we only support LED message type right now */ 2594*18f7ba4cSKristen Carlson Accardi if ((messages & 0x01) && (ahci_em_messages == 1)) { 2595*18f7ba4cSKristen Carlson Accardi /* store em_loc */ 2596*18f7ba4cSKristen Carlson Accardi hpriv->em_loc = ((em_loc >> 16) * 4); 2597*18f7ba4cSKristen Carlson Accardi pi.flags |= ATA_FLAG_EM; 2598*18f7ba4cSKristen Carlson Accardi if (!(em_ctl & EM_CTL_ALHD)) 2599*18f7ba4cSKristen Carlson Accardi pi.flags |= ATA_FLAG_SW_ACTIVITY; 2600*18f7ba4cSKristen Carlson Accardi } 2601*18f7ba4cSKristen Carlson Accardi } 2602*18f7ba4cSKristen Carlson Accardi 2603837f5f8fSTejun Heo /* CAP.NP sometimes indicate the index of the last enabled 2604837f5f8fSTejun Heo * port, at other times, that of the last possible port, so 2605837f5f8fSTejun Heo * determining the maximum port number requires looking at 2606837f5f8fSTejun Heo * both CAP.NP and port_map. 2607837f5f8fSTejun Heo */ 2608837f5f8fSTejun Heo n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 2609837f5f8fSTejun Heo 2610837f5f8fSTejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 26114447d351STejun Heo if (!host) 26124447d351STejun Heo return -ENOMEM; 26134447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 26144447d351STejun Heo host->private_data = hpriv; 26154447d351STejun Heo 2616*18f7ba4cSKristen Carlson Accardi if (pi.flags & ATA_FLAG_EM) 2617*18f7ba4cSKristen Carlson Accardi ahci_reset_em(host); 2618*18f7ba4cSKristen Carlson Accardi 26194447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 26204447d351STejun Heo struct ata_port *ap = host->ports[i]; 26214447d351STejun Heo 2622cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); 2623cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, 2624cbcdd875STejun Heo 0x100 + ap->port_no * 0x80, "port"); 2625cbcdd875STejun Heo 262631556594SKristen Carlson Accardi /* set initial link pm policy */ 262731556594SKristen Carlson Accardi ap->pm_policy = NOT_AVAILABLE; 262831556594SKristen Carlson Accardi 2629*18f7ba4cSKristen Carlson Accardi /* set enclosure management message type */ 2630*18f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_EM) 2631*18f7ba4cSKristen Carlson Accardi ap->em_message_type = ahci_em_messages; 2632*18f7ba4cSKristen Carlson Accardi 2633*18f7ba4cSKristen Carlson Accardi 2634dab632e8SJeff Garzik /* disabled/not-implemented port */ 2635350756f6STejun Heo if (!(hpriv->port_map & (1 << i))) 2636dab632e8SJeff Garzik ap->ops = &ata_dummy_port_ops; 26374447d351STejun Heo } 2638c6fd2807SJeff Garzik 2639edc93052STejun Heo /* apply workaround for ASUS P5W DH Deluxe mainboard */ 2640edc93052STejun Heo ahci_p5wdh_workaround(host); 2641edc93052STejun Heo 2642c6fd2807SJeff Garzik /* initialize adapter */ 26434447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2644c6fd2807SJeff Garzik if (rc) 264524dc5f33STejun Heo return rc; 2646c6fd2807SJeff Garzik 26474447d351STejun Heo rc = ahci_reset_controller(host); 26484447d351STejun Heo if (rc) 26494447d351STejun Heo return rc; 2650c6fd2807SJeff Garzik 26514447d351STejun Heo ahci_init_controller(host); 26524447d351STejun Heo ahci_print_info(host); 2653c6fd2807SJeff Garzik 26544447d351STejun Heo pci_set_master(pdev); 26554447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 26564447d351STejun Heo &ahci_sht); 2657c6fd2807SJeff Garzik } 2658c6fd2807SJeff Garzik 2659c6fd2807SJeff Garzik static int __init ahci_init(void) 2660c6fd2807SJeff Garzik { 2661c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 2662c6fd2807SJeff Garzik } 2663c6fd2807SJeff Garzik 2664c6fd2807SJeff Garzik static void __exit ahci_exit(void) 2665c6fd2807SJeff Garzik { 2666c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 2667c6fd2807SJeff Garzik } 2668c6fd2807SJeff Garzik 2669c6fd2807SJeff Garzik 2670c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 2671c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 2672c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2673c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 2674c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2675c6fd2807SJeff Garzik 2676c6fd2807SJeff Garzik module_init(ahci_init); 2677c6fd2807SJeff Garzik module_exit(ahci_exit); 2678