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); 5918f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf); 6018f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, 6118f7ba4cSKristen Carlson Accardi size_t size); 6218f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, 6318f7ba4cSKristen Carlson Accardi ssize_t size); 6418f7ba4cSKristen 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 */ 10718f7ba4cSKristen Carlson Accardi HOST_EM_LOC = 0x1c, /* Enclosure Management location */ 10818f7ba4cSKristen 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 */ 11618f7ba4cSKristen 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 */ 21418f7ba4cSKristen Carlson Accardi 21518f7ba4cSKristen Carlson Accardi /* em_ctl bits */ 21618f7ba4cSKristen Carlson Accardi EM_CTL_RST = (1 << 9), /* Reset */ 21718f7ba4cSKristen Carlson Accardi EM_CTL_TM = (1 << 8), /* Transmit Message */ 21818f7ba4cSKristen 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 23618f7ba4cSKristen Carlson Accardi struct ahci_em_priv { 23718f7ba4cSKristen Carlson Accardi enum sw_activity blink_policy; 23818f7ba4cSKristen Carlson Accardi struct timer_list timer; 23918f7ba4cSKristen Carlson Accardi unsigned long saved_activity; 24018f7ba4cSKristen Carlson Accardi unsigned long activity; 24118f7ba4cSKristen Carlson Accardi unsigned long led_state; 24218f7ba4cSKristen Carlson Accardi }; 24318f7ba4cSKristen 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 */ 25018f7ba4cSKristen 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 */ 26618f7ba4cSKristen Carlson Accardi struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info 26718f7ba4cSKristen Carlson Accardi * per PM slot */ 268c6fd2807SJeff Garzik }; 269c6fd2807SJeff Garzik 27082ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); 27182ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, 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 30518f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf); 30618f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, 30718f7ba4cSKristen Carlson Accardi enum sw_activity val); 30818f7ba4cSKristen 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, 31218f7ba4cSKristen Carlson Accardi &dev_attr_em_message_type, 31318f7ba4cSKristen Carlson Accardi &dev_attr_em_message, 31418f7ba4cSKristen Carlson Accardi NULL 31518f7ba4cSKristen Carlson Accardi }; 31618f7ba4cSKristen Carlson Accardi 31718f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = { 31818f7ba4cSKristen Carlson Accardi &dev_attr_sw_activity, 31945fabbb7SElias Oltmanns &dev_attr_unload_heads, 32031556594SKristen Carlson Accardi NULL 32131556594SKristen Carlson Accardi }; 32231556594SKristen Carlson Accardi 323c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = { 32468d1d07bSTejun Heo ATA_NCQ_SHT(DRV_NAME), 325c6fd2807SJeff Garzik .can_queue = AHCI_MAX_CMDS - 1, 326c6fd2807SJeff Garzik .sg_tablesize = AHCI_MAX_SG, 327c6fd2807SJeff Garzik .dma_boundary = AHCI_DMA_BOUNDARY, 32831556594SKristen Carlson Accardi .shost_attrs = ahci_shost_attrs, 32918f7ba4cSKristen Carlson Accardi .sdev_attrs = ahci_sdev_attrs, 330c6fd2807SJeff Garzik }; 331c6fd2807SJeff Garzik 332029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = { 333029cfd6bSTejun Heo .inherits = &sata_pmp_port_ops, 334029cfd6bSTejun Heo 3357d50b60bSTejun Heo .qc_defer = sata_pmp_qc_defer_cmd_switch, 336c6fd2807SJeff Garzik .qc_prep = ahci_qc_prep, 337c6fd2807SJeff Garzik .qc_issue = ahci_qc_issue, 3384c9bf4e7STejun Heo .qc_fill_rtf = ahci_qc_fill_rtf, 339c6fd2807SJeff Garzik 340c6fd2807SJeff Garzik .freeze = ahci_freeze, 341c6fd2807SJeff Garzik .thaw = ahci_thaw, 342a1efdabaSTejun Heo .softreset = ahci_softreset, 343a1efdabaSTejun Heo .hardreset = ahci_hardreset, 344a1efdabaSTejun Heo .postreset = ahci_postreset, 345071f44b1STejun Heo .pmp_softreset = ahci_softreset, 346c6fd2807SJeff Garzik .error_handler = ahci_error_handler, 347c6fd2807SJeff Garzik .post_internal_cmd = ahci_post_internal_cmd, 348029cfd6bSTejun Heo .dev_config = ahci_dev_config, 349c6fd2807SJeff Garzik 350029cfd6bSTejun Heo .scr_read = ahci_scr_read, 351029cfd6bSTejun Heo .scr_write = ahci_scr_write, 3527d50b60bSTejun Heo .pmp_attach = ahci_pmp_attach, 3537d50b60bSTejun Heo .pmp_detach = ahci_pmp_detach, 3547d50b60bSTejun Heo 355029cfd6bSTejun Heo .enable_pm = ahci_enable_alpm, 356029cfd6bSTejun Heo .disable_pm = ahci_disable_alpm, 35718f7ba4cSKristen Carlson Accardi .em_show = ahci_led_show, 35818f7ba4cSKristen Carlson Accardi .em_store = ahci_led_store, 35918f7ba4cSKristen Carlson Accardi .sw_activity_show = ahci_activity_show, 36018f7ba4cSKristen Carlson Accardi .sw_activity_store = ahci_activity_store, 361438ac6d5STejun Heo #ifdef CONFIG_PM 362c6fd2807SJeff Garzik .port_suspend = ahci_port_suspend, 363c6fd2807SJeff Garzik .port_resume = ahci_port_resume, 364438ac6d5STejun Heo #endif 365c6fd2807SJeff Garzik .port_start = ahci_port_start, 366c6fd2807SJeff Garzik .port_stop = ahci_port_stop, 367c6fd2807SJeff Garzik }; 368c6fd2807SJeff Garzik 369029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = { 370029cfd6bSTejun Heo .inherits = &ahci_ops, 371a1efdabaSTejun Heo .hardreset = ahci_vt8251_hardreset, 372ad616ffbSTejun Heo }; 373ad616ffbSTejun Heo 374029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = { 375029cfd6bSTejun Heo .inherits = &ahci_ops, 376a1efdabaSTejun Heo .hardreset = ahci_p5wdh_hardreset, 377edc93052STejun Heo }; 378edc93052STejun Heo 379bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = { 380bd17243aSShane Huang .inherits = &ahci_ops, 381bd17243aSShane Huang .softreset = ahci_sb600_softreset, 382bd17243aSShane Huang .pmp_softreset = ahci_sb600_softreset, 383bd17243aSShane Huang }; 384bd17243aSShane Huang 385417a1a6dSTejun Heo #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 386417a1a6dSTejun Heo 387c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = { 388c6fd2807SJeff Garzik /* board_ahci */ 389c6fd2807SJeff Garzik { 3901188c0d8STejun Heo .flags = AHCI_FLAG_COMMON, 391c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 392469248abSJeff Garzik .udma_mask = ATA_UDMA6, 393c6fd2807SJeff Garzik .port_ops = &ahci_ops, 394c6fd2807SJeff Garzik }, 395c6fd2807SJeff Garzik /* board_ahci_vt8251 */ 396c6fd2807SJeff Garzik { 3976949b914STejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), 398417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 399c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 400469248abSJeff Garzik .udma_mask = ATA_UDMA6, 401ad616ffbSTejun Heo .port_ops = &ahci_vt8251_ops, 402c6fd2807SJeff Garzik }, 40341669553STejun Heo /* board_ahci_ign_iferr */ 40441669553STejun Heo { 405417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), 406417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 40741669553STejun Heo .pio_mask = 0x1f, /* pio0-4 */ 408469248abSJeff Garzik .udma_mask = ATA_UDMA6, 40941669553STejun Heo .port_ops = &ahci_ops, 41041669553STejun Heo }, 41155a61604SConke Hu /* board_ahci_sb600 */ 41255a61604SConke Hu { 413417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 41422b5e7a7STejun Heo AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | 415bd17243aSShane Huang AHCI_HFLAG_SECT255), 416417a1a6dSTejun Heo .flags = AHCI_FLAG_COMMON, 41755a61604SConke Hu .pio_mask = 0x1f, /* pio0-4 */ 418469248abSJeff Garzik .udma_mask = ATA_UDMA6, 419bd17243aSShane Huang .port_ops = &ahci_sb600_ops, 42055a61604SConke Hu }, 421cd70c266SJeff Garzik /* board_ahci_mv */ 422cd70c266SJeff Garzik { 423417a1a6dSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | 42417248461STejun Heo AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), 425cd70c266SJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 426417a1a6dSTejun Heo ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 427cd70c266SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 428cd70c266SJeff Garzik .udma_mask = ATA_UDMA6, 429cd70c266SJeff Garzik .port_ops = &ahci_ops, 430cd70c266SJeff Garzik }, 431e39fc8c9SShane Huang /* board_ahci_sb700 */ 432e39fc8c9SShane Huang { 433bd17243aSShane Huang AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), 434e39fc8c9SShane Huang .flags = AHCI_FLAG_COMMON, 435e39fc8c9SShane Huang .pio_mask = 0x1f, /* pio0-4 */ 436e39fc8c9SShane Huang .udma_mask = ATA_UDMA6, 437bd17243aSShane Huang .port_ops = &ahci_sb600_ops, 438e39fc8c9SShane Huang }, 439e297d99eSTejun Heo /* board_ahci_mcp65 */ 440e297d99eSTejun Heo { 441e297d99eSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), 442e297d99eSTejun Heo .flags = AHCI_FLAG_COMMON, 443e297d99eSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 444e297d99eSTejun Heo .udma_mask = ATA_UDMA6, 445e297d99eSTejun Heo .port_ops = &ahci_ops, 446e297d99eSTejun Heo }, 4479a3b103cSTejun Heo /* board_ahci_nopmp */ 4489a3b103cSTejun Heo { 4499a3b103cSTejun Heo AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), 4509a3b103cSTejun Heo .flags = AHCI_FLAG_COMMON, 4519a3b103cSTejun Heo .pio_mask = 0x1f, /* pio0-4 */ 4529a3b103cSTejun Heo .udma_mask = ATA_UDMA6, 4539a3b103cSTejun Heo .port_ops = &ahci_ops, 4549a3b103cSTejun Heo }, 455c6fd2807SJeff Garzik }; 456c6fd2807SJeff Garzik 457c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = { 458c6fd2807SJeff Garzik /* Intel */ 45954bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */ 46054bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */ 46154bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */ 46254bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */ 46354bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */ 46482490c09STejun Heo { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */ 46554bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */ 46654bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ 46754bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ 46854bb3a94SJeff Garzik { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ 4697a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ 4707a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ 4717a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ 4727a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ 4737a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ 4747a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ 4757a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ 4767a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ 4777a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ 4787a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ 4797a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ 4807a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ 4817a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ 4827a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ 4837a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ 4847a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ 4857a234affSTejun Heo { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ 486d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ 487d4155e6fSJason Gaston { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ 48816ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ 48916ad1ad9SJason Gaston { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */ 490adcb5308SSeth Heasley { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */ 4918e48b6b3SSeth Heasley { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */ 492adcb5308SSeth Heasley { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ 4938e48b6b3SSeth Heasley { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ 494c6fd2807SJeff Garzik 495e34bb370STejun Heo /* JMicron 360/1/3/5/6, match class to avoid IDE function */ 496e34bb370STejun Heo { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 497e34bb370STejun Heo PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, 498c6fd2807SJeff Garzik 499c6fd2807SJeff Garzik /* ATI */ 500c65ec1c2SConke Hu { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ 501e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */ 502e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */ 503e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */ 504e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */ 505e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ 506e39fc8c9SShane Huang { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ 507c6fd2807SJeff Garzik 508c6fd2807SJeff Garzik /* VIA */ 50954bb3a94SJeff Garzik { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ 510bf335542STejun Heo { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ 511c6fd2807SJeff Garzik 512c6fd2807SJeff Garzik /* NVIDIA */ 513e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */ 514e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */ 515e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */ 516e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */ 517e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */ 518e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */ 519e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */ 520e297d99eSTejun Heo { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */ 5216fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ 5226fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ 5236fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ 5246fbf5ba4SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */ 525895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */ 526895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */ 527895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */ 528895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */ 529895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */ 530895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */ 531895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */ 532895663cdSPeer Chen { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */ 5330522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */ 5340522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */ 5350522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */ 5360522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */ 5370522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */ 5380522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */ 5390522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */ 5400522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */ 5410522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */ 5420522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */ 5430522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */ 5440522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */ 5450522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */ 5460522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */ 5470522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */ 5480522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */ 5490522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */ 5500522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */ 5510522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */ 5520522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */ 5530522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */ 5540522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ 5550522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ 5560522b286SPeer Chen { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ 5576ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */ 5586ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */ 5596ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */ 5606ba86958Speerchen { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */ 5617100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ 5627100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ 5637100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ 5647100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ 5657100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ 5667100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ 5677100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ 5687100819fSPeer Chen { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ 56970d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */ 57070d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */ 57170d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */ 57270d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */ 57370d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */ 57470d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ 57570d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ 57670d562cfSpeerchen { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ 5773072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */ 5783072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */ 5793072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */ 5803072c379Speerchen { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */ 581c6fd2807SJeff Garzik 582c6fd2807SJeff Garzik /* SiS */ 58320e2de4aSTejun Heo { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ 58420e2de4aSTejun Heo { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 968 */ 58520e2de4aSTejun Heo { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ 586c6fd2807SJeff Garzik 587cd70c266SJeff Garzik /* Marvell */ 588cd70c266SJeff Garzik { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ 589c40e7cb8SJose Alberto Reguero { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ 590cd70c266SJeff Garzik 591*c77a036bSMark Nelson /* Promise */ 592*c77a036bSMark Nelson { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ 593*c77a036bSMark Nelson 594415ae2b5SJeff Garzik /* Generic, PCI class code for AHCI */ 595415ae2b5SJeff Garzik { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 596c9f89475SConke Hu PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, 597415ae2b5SJeff Garzik 598c6fd2807SJeff Garzik { } /* terminate list */ 599c6fd2807SJeff Garzik }; 600c6fd2807SJeff Garzik 601c6fd2807SJeff Garzik 602c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = { 603c6fd2807SJeff Garzik .name = DRV_NAME, 604c6fd2807SJeff Garzik .id_table = ahci_pci_tbl, 605c6fd2807SJeff Garzik .probe = ahci_init_one, 60624dc5f33STejun Heo .remove = ata_pci_remove_one, 607438ac6d5STejun Heo #ifdef CONFIG_PM 608c6fd2807SJeff Garzik .suspend = ahci_pci_device_suspend, 609c6fd2807SJeff Garzik .resume = ahci_pci_device_resume, 610438ac6d5STejun Heo #endif 611c6fd2807SJeff Garzik }; 612c6fd2807SJeff Garzik 61318f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1; 61418f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444); 61518f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */ 61618f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages, 61718f7ba4cSKristen Carlson Accardi "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED"); 618c6fd2807SJeff Garzik 6195b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE) 6205b66c829SAlan Cox static int marvell_enable; 6215b66c829SAlan Cox #else 6225b66c829SAlan Cox static int marvell_enable = 1; 6235b66c829SAlan Cox #endif 6245b66c829SAlan Cox module_param(marvell_enable, int, 0644); 6255b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); 6265b66c829SAlan Cox 6275b66c829SAlan Cox 62898fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap) 62998fa4b60STejun Heo { 63098fa4b60STejun Heo return (cap & 0x1f) + 1; 63198fa4b60STejun Heo } 63298fa4b60STejun Heo 633dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host, 634dab632e8SJeff Garzik unsigned int port_no) 635dab632e8SJeff Garzik { 636dab632e8SJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 637dab632e8SJeff Garzik 638dab632e8SJeff Garzik return mmio + 0x100 + (port_no * 0x80); 639dab632e8SJeff Garzik } 640dab632e8SJeff Garzik 6414447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap) 642c6fd2807SJeff Garzik { 643dab632e8SJeff Garzik return __ahci_port_base(ap->host, ap->port_no); 644c6fd2807SJeff Garzik } 645c6fd2807SJeff Garzik 646b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio) 647b710a1f4STejun Heo { 64815fe982eSTejun Heo int i; 649b710a1f4STejun Heo u32 tmp; 650b710a1f4STejun Heo 651b710a1f4STejun Heo /* turn on AHCI_EN */ 652b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 65315fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 65415fe982eSTejun Heo return; 65515fe982eSTejun Heo 65615fe982eSTejun Heo /* Some controllers need AHCI_EN to be written multiple times. 65715fe982eSTejun Heo * Try a few times before giving up. 65815fe982eSTejun Heo */ 65915fe982eSTejun Heo for (i = 0; i < 5; i++) { 660b710a1f4STejun Heo tmp |= HOST_AHCI_EN; 661b710a1f4STejun Heo writel(tmp, mmio + HOST_CTL); 662b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ 66315fe982eSTejun Heo if (tmp & HOST_AHCI_EN) 66415fe982eSTejun Heo return; 66515fe982eSTejun Heo msleep(10); 666b710a1f4STejun Heo } 66715fe982eSTejun Heo 66815fe982eSTejun Heo WARN_ON(1); 669b710a1f4STejun Heo } 670b710a1f4STejun Heo 671d447df14STejun Heo /** 672d447df14STejun Heo * ahci_save_initial_config - Save and fixup initial config values 6734447d351STejun Heo * @pdev: target PCI device 6744447d351STejun Heo * @hpriv: host private area to store config values 675d447df14STejun Heo * 676d447df14STejun Heo * Some registers containing configuration info might be setup by 677d447df14STejun Heo * BIOS and might be cleared on reset. This function saves the 678d447df14STejun Heo * initial values of those registers into @hpriv such that they 679d447df14STejun Heo * can be restored after controller reset. 680d447df14STejun Heo * 681d447df14STejun Heo * If inconsistent, config values are fixed up by this function. 682d447df14STejun Heo * 683d447df14STejun Heo * LOCKING: 684d447df14STejun Heo * None. 685d447df14STejun Heo */ 6864447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev, 6874447d351STejun Heo struct ahci_host_priv *hpriv) 688d447df14STejun Heo { 6894447d351STejun Heo void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 690d447df14STejun Heo u32 cap, port_map; 69117199b18STejun Heo int i; 692c40e7cb8SJose Alberto Reguero int mv; 693d447df14STejun Heo 694b710a1f4STejun Heo /* make sure AHCI mode is enabled before accessing CAP */ 695b710a1f4STejun Heo ahci_enable_ahci(mmio); 696b710a1f4STejun Heo 697d447df14STejun Heo /* Values prefixed with saved_ are written back to host after 698d447df14STejun Heo * reset. Values without are used for driver operation. 699d447df14STejun Heo */ 700d447df14STejun Heo hpriv->saved_cap = cap = readl(mmio + HOST_CAP); 701d447df14STejun Heo hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 702d447df14STejun Heo 703274c1fdeSTejun Heo /* some chips have errata preventing 64bit use */ 704417a1a6dSTejun Heo if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { 705c7a42156STejun Heo dev_printk(KERN_INFO, &pdev->dev, 706c7a42156STejun Heo "controller can't do 64bit DMA, forcing 32bit\n"); 707c7a42156STejun Heo cap &= ~HOST_CAP_64; 708c7a42156STejun Heo } 709c7a42156STejun Heo 710417a1a6dSTejun Heo if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { 711274c1fdeSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 712274c1fdeSTejun Heo "controller can't do NCQ, turning off CAP_NCQ\n"); 713274c1fdeSTejun Heo cap &= ~HOST_CAP_NCQ; 714274c1fdeSTejun Heo } 715274c1fdeSTejun Heo 716e297d99eSTejun Heo if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { 717e297d99eSTejun Heo dev_printk(KERN_INFO, &pdev->dev, 718e297d99eSTejun Heo "controller can do NCQ, turning on CAP_NCQ\n"); 719e297d99eSTejun Heo cap |= HOST_CAP_NCQ; 720e297d99eSTejun Heo } 721e297d99eSTejun Heo 722258cd846SRoel Kluin if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { 7236949b914STejun Heo dev_printk(KERN_INFO, &pdev->dev, 7246949b914STejun Heo "controller can't do PMP, turning off CAP_PMP\n"); 7256949b914STejun Heo cap &= ~HOST_CAP_PMP; 7266949b914STejun Heo } 7276949b914STejun Heo 728d799e083STejun Heo if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && 729d799e083STejun Heo port_map != 1) { 730d799e083STejun Heo dev_printk(KERN_INFO, &pdev->dev, 731d799e083STejun Heo "JMB361 has only one port, port_map 0x%x -> 0x%x\n", 732d799e083STejun Heo port_map, 1); 733d799e083STejun Heo port_map = 1; 734d799e083STejun Heo } 735d799e083STejun Heo 736cd70c266SJeff Garzik /* 737cd70c266SJeff Garzik * Temporary Marvell 6145 hack: PATA port presence 738cd70c266SJeff Garzik * is asserted through the standard AHCI port 739cd70c266SJeff Garzik * presence register, as bit 4 (counting from 0) 740cd70c266SJeff Garzik */ 741417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 742c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 743c40e7cb8SJose Alberto Reguero mv = 0x3; 744c40e7cb8SJose Alberto Reguero else 745c40e7cb8SJose Alberto Reguero mv = 0xf; 746cd70c266SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 747cd70c266SJeff Garzik "MV_AHCI HACK: port_map %x -> %x\n", 748c40e7cb8SJose Alberto Reguero port_map, 749c40e7cb8SJose Alberto Reguero port_map & mv); 7505b66c829SAlan Cox dev_printk(KERN_ERR, &pdev->dev, 7515b66c829SAlan Cox "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); 752cd70c266SJeff Garzik 753c40e7cb8SJose Alberto Reguero port_map &= mv; 754cd70c266SJeff Garzik } 755cd70c266SJeff Garzik 75617199b18STejun Heo /* cross check port_map and cap.n_ports */ 7577a234affSTejun Heo if (port_map) { 758837f5f8fSTejun Heo int map_ports = 0; 75917199b18STejun Heo 760837f5f8fSTejun Heo for (i = 0; i < AHCI_MAX_PORTS; i++) 761837f5f8fSTejun Heo if (port_map & (1 << i)) 762837f5f8fSTejun Heo map_ports++; 76317199b18STejun Heo 764837f5f8fSTejun Heo /* If PI has more ports than n_ports, whine, clear 765837f5f8fSTejun Heo * port_map and let it be generated from n_ports. 76617199b18STejun Heo */ 767837f5f8fSTejun Heo if (map_ports > ahci_nr_ports(cap)) { 7684447d351STejun Heo dev_printk(KERN_WARNING, &pdev->dev, 769837f5f8fSTejun Heo "implemented port map (0x%x) contains more " 770837f5f8fSTejun Heo "ports than nr_ports (%u), using nr_ports\n", 771837f5f8fSTejun Heo port_map, ahci_nr_ports(cap)); 7727a234affSTejun Heo port_map = 0; 7737a234affSTejun Heo } 7747a234affSTejun Heo } 7757a234affSTejun Heo 77617199b18STejun Heo /* fabricate port_map from cap.nr_ports */ 7777a234affSTejun Heo if (!port_map) { 77817199b18STejun Heo port_map = (1 << ahci_nr_ports(cap)) - 1; 7797a234affSTejun Heo dev_printk(KERN_WARNING, &pdev->dev, 7807a234affSTejun Heo "forcing PORTS_IMPL to 0x%x\n", port_map); 7817a234affSTejun Heo 7827a234affSTejun Heo /* write the fixed up value to the PI register */ 7837a234affSTejun Heo hpriv->saved_port_map = port_map; 78417199b18STejun Heo } 78517199b18STejun Heo 786d447df14STejun Heo /* record values to use during operation */ 787d447df14STejun Heo hpriv->cap = cap; 788d447df14STejun Heo hpriv->port_map = port_map; 789d447df14STejun Heo } 790d447df14STejun Heo 791d447df14STejun Heo /** 792d447df14STejun Heo * ahci_restore_initial_config - Restore initial config 7934447d351STejun Heo * @host: target ATA host 794d447df14STejun Heo * 795d447df14STejun Heo * Restore initial config stored by ahci_save_initial_config(). 796d447df14STejun Heo * 797d447df14STejun Heo * LOCKING: 798d447df14STejun Heo * None. 799d447df14STejun Heo */ 8004447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host) 801d447df14STejun Heo { 8024447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 8034447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 8044447d351STejun Heo 805d447df14STejun Heo writel(hpriv->saved_cap, mmio + HOST_CAP); 806d447df14STejun Heo writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); 807d447df14STejun Heo (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ 808d447df14STejun Heo } 809d447df14STejun Heo 810203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) 811c6fd2807SJeff Garzik { 812203ef6c4STejun Heo static const int offset[] = { 813203ef6c4STejun Heo [SCR_STATUS] = PORT_SCR_STAT, 814203ef6c4STejun Heo [SCR_CONTROL] = PORT_SCR_CTL, 815203ef6c4STejun Heo [SCR_ERROR] = PORT_SCR_ERR, 816203ef6c4STejun Heo [SCR_ACTIVE] = PORT_SCR_ACT, 817203ef6c4STejun Heo [SCR_NOTIFICATION] = PORT_SCR_NTF, 818203ef6c4STejun Heo }; 819203ef6c4STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 820c6fd2807SJeff Garzik 821203ef6c4STejun Heo if (sc_reg < ARRAY_SIZE(offset) && 822203ef6c4STejun Heo (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) 823203ef6c4STejun Heo return offset[sc_reg]; 824da3dbb17STejun Heo return 0; 825c6fd2807SJeff Garzik } 826c6fd2807SJeff Garzik 82782ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) 828c6fd2807SJeff Garzik { 82982ef04fbSTejun Heo void __iomem *port_mmio = ahci_port_base(link->ap); 83082ef04fbSTejun Heo int offset = ahci_scr_offset(link->ap, sc_reg); 831c6fd2807SJeff Garzik 832203ef6c4STejun Heo if (offset) { 833203ef6c4STejun Heo *val = readl(port_mmio + offset); 834203ef6c4STejun Heo return 0; 835203ef6c4STejun Heo } 836da3dbb17STejun Heo return -EINVAL; 837c6fd2807SJeff Garzik } 838c6fd2807SJeff Garzik 83982ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) 840203ef6c4STejun Heo { 84182ef04fbSTejun Heo void __iomem *port_mmio = ahci_port_base(link->ap); 84282ef04fbSTejun Heo int offset = ahci_scr_offset(link->ap, sc_reg); 843203ef6c4STejun Heo 844203ef6c4STejun Heo if (offset) { 845203ef6c4STejun Heo writel(val, port_mmio + offset); 846da3dbb17STejun Heo return 0; 847c6fd2807SJeff Garzik } 848203ef6c4STejun Heo return -EINVAL; 849203ef6c4STejun Heo } 850c6fd2807SJeff Garzik 8514447d351STejun Heo static void ahci_start_engine(struct ata_port *ap) 852c6fd2807SJeff Garzik { 8534447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 854c6fd2807SJeff Garzik u32 tmp; 855c6fd2807SJeff Garzik 856c6fd2807SJeff Garzik /* start DMA */ 857c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 858c6fd2807SJeff Garzik tmp |= PORT_CMD_START; 859c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 860c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 861c6fd2807SJeff Garzik } 862c6fd2807SJeff Garzik 8634447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap) 864c6fd2807SJeff Garzik { 8654447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 866c6fd2807SJeff Garzik u32 tmp; 867c6fd2807SJeff Garzik 868c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 869c6fd2807SJeff Garzik 870c6fd2807SJeff Garzik /* check if the HBA is idle */ 871c6fd2807SJeff Garzik if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) 872c6fd2807SJeff Garzik return 0; 873c6fd2807SJeff Garzik 874c6fd2807SJeff Garzik /* setting HBA to idle */ 875c6fd2807SJeff Garzik tmp &= ~PORT_CMD_START; 876c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 877c6fd2807SJeff Garzik 878c6fd2807SJeff Garzik /* wait for engine to stop. This could be as long as 500 msec */ 879c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 880c6fd2807SJeff Garzik PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); 881c6fd2807SJeff Garzik if (tmp & PORT_CMD_LIST_ON) 882c6fd2807SJeff Garzik return -EIO; 883c6fd2807SJeff Garzik 884c6fd2807SJeff Garzik return 0; 885c6fd2807SJeff Garzik } 886c6fd2807SJeff Garzik 8874447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap) 888c6fd2807SJeff Garzik { 8894447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 8904447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 8914447d351STejun Heo struct ahci_port_priv *pp = ap->private_data; 892c6fd2807SJeff Garzik u32 tmp; 893c6fd2807SJeff Garzik 894c6fd2807SJeff Garzik /* set FIS registers */ 8954447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 8964447d351STejun Heo writel((pp->cmd_slot_dma >> 16) >> 16, 8974447d351STejun Heo port_mmio + PORT_LST_ADDR_HI); 8984447d351STejun Heo writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); 899c6fd2807SJeff Garzik 9004447d351STejun Heo if (hpriv->cap & HOST_CAP_64) 9014447d351STejun Heo writel((pp->rx_fis_dma >> 16) >> 16, 9024447d351STejun Heo port_mmio + PORT_FIS_ADDR_HI); 9034447d351STejun Heo writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); 904c6fd2807SJeff Garzik 905c6fd2807SJeff Garzik /* enable FIS reception */ 906c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 907c6fd2807SJeff Garzik tmp |= PORT_CMD_FIS_RX; 908c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 909c6fd2807SJeff Garzik 910c6fd2807SJeff Garzik /* flush */ 911c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); 912c6fd2807SJeff Garzik } 913c6fd2807SJeff Garzik 9144447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap) 915c6fd2807SJeff Garzik { 9164447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 917c6fd2807SJeff Garzik u32 tmp; 918c6fd2807SJeff Garzik 919c6fd2807SJeff Garzik /* disable FIS reception */ 920c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 921c6fd2807SJeff Garzik tmp &= ~PORT_CMD_FIS_RX; 922c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 923c6fd2807SJeff Garzik 924c6fd2807SJeff Garzik /* wait for completion, spec says 500ms, give it 1000 */ 925c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, 926c6fd2807SJeff Garzik PORT_CMD_FIS_ON, 10, 1000); 927c6fd2807SJeff Garzik if (tmp & PORT_CMD_FIS_ON) 928c6fd2807SJeff Garzik return -EBUSY; 929c6fd2807SJeff Garzik 930c6fd2807SJeff Garzik return 0; 931c6fd2807SJeff Garzik } 932c6fd2807SJeff Garzik 9334447d351STejun Heo static void ahci_power_up(struct ata_port *ap) 934c6fd2807SJeff Garzik { 9354447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 9364447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 937c6fd2807SJeff Garzik u32 cmd; 938c6fd2807SJeff Garzik 939c6fd2807SJeff Garzik cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 940c6fd2807SJeff Garzik 941c6fd2807SJeff Garzik /* spin up device */ 9424447d351STejun Heo if (hpriv->cap & HOST_CAP_SSS) { 943c6fd2807SJeff Garzik cmd |= PORT_CMD_SPIN_UP; 944c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 945c6fd2807SJeff Garzik } 946c6fd2807SJeff Garzik 947c6fd2807SJeff Garzik /* wake up link */ 948c6fd2807SJeff Garzik writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); 949c6fd2807SJeff Garzik } 950c6fd2807SJeff Garzik 95131556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap) 95231556594SKristen Carlson Accardi { 95331556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 95431556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 95531556594SKristen Carlson Accardi u32 cmd; 95631556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 95731556594SKristen Carlson Accardi 95831556594SKristen Carlson Accardi /* IPM bits should be disabled by libata-core */ 95931556594SKristen Carlson Accardi /* get the existing command bits */ 96031556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 96131556594SKristen Carlson Accardi 96231556594SKristen Carlson Accardi /* disable ALPM and ASP */ 96331556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ASP; 96431556594SKristen Carlson Accardi cmd &= ~PORT_CMD_ALPE; 96531556594SKristen Carlson Accardi 96631556594SKristen Carlson Accardi /* force the interface back to active */ 96731556594SKristen Carlson Accardi cmd |= PORT_CMD_ICC_ACTIVE; 96831556594SKristen Carlson Accardi 96931556594SKristen Carlson Accardi /* write out new cmd value */ 97031556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 97131556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 97231556594SKristen Carlson Accardi 97331556594SKristen Carlson Accardi /* wait 10ms to be sure we've come out of any low power state */ 97431556594SKristen Carlson Accardi msleep(10); 97531556594SKristen Carlson Accardi 97631556594SKristen Carlson Accardi /* clear out any PhyRdy stuff from interrupt status */ 97731556594SKristen Carlson Accardi writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); 97831556594SKristen Carlson Accardi 97931556594SKristen Carlson Accardi /* go ahead and clean out PhyRdy Change from Serror too */ 98082ef04fbSTejun Heo ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); 98131556594SKristen Carlson Accardi 98231556594SKristen Carlson Accardi /* 98331556594SKristen Carlson Accardi * Clear flag to indicate that we should ignore all PhyRdy 98431556594SKristen Carlson Accardi * state changes 98531556594SKristen Carlson Accardi */ 98631556594SKristen Carlson Accardi hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; 98731556594SKristen Carlson Accardi 98831556594SKristen Carlson Accardi /* 98931556594SKristen Carlson Accardi * Enable interrupts on Phy Ready. 99031556594SKristen Carlson Accardi */ 99131556594SKristen Carlson Accardi pp->intr_mask |= PORT_IRQ_PHYRDY; 99231556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 99331556594SKristen Carlson Accardi 99431556594SKristen Carlson Accardi /* 99531556594SKristen Carlson Accardi * don't change the link pm policy - we can be called 99631556594SKristen Carlson Accardi * just to turn of link pm temporarily 99731556594SKristen Carlson Accardi */ 99831556594SKristen Carlson Accardi } 99931556594SKristen Carlson Accardi 100031556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap, 100131556594SKristen Carlson Accardi enum link_pm policy) 100231556594SKristen Carlson Accardi { 100331556594SKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 100431556594SKristen Carlson Accardi void __iomem *port_mmio = ahci_port_base(ap); 100531556594SKristen Carlson Accardi u32 cmd; 100631556594SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 100731556594SKristen Carlson Accardi u32 asp; 100831556594SKristen Carlson Accardi 100931556594SKristen Carlson Accardi /* Make sure the host is capable of link power management */ 101031556594SKristen Carlson Accardi if (!(hpriv->cap & HOST_CAP_ALPM)) 101131556594SKristen Carlson Accardi return -EINVAL; 101231556594SKristen Carlson Accardi 101331556594SKristen Carlson Accardi switch (policy) { 101431556594SKristen Carlson Accardi case MAX_PERFORMANCE: 101531556594SKristen Carlson Accardi case NOT_AVAILABLE: 101631556594SKristen Carlson Accardi /* 101731556594SKristen Carlson Accardi * if we came here with NOT_AVAILABLE, 101831556594SKristen Carlson Accardi * it just means this is the first time we 101931556594SKristen Carlson Accardi * have tried to enable - default to max performance, 102031556594SKristen Carlson Accardi * and let the user go to lower power modes on request. 102131556594SKristen Carlson Accardi */ 102231556594SKristen Carlson Accardi ahci_disable_alpm(ap); 102331556594SKristen Carlson Accardi return 0; 102431556594SKristen Carlson Accardi case MIN_POWER: 102531556594SKristen Carlson Accardi /* configure HBA to enter SLUMBER */ 102631556594SKristen Carlson Accardi asp = PORT_CMD_ASP; 102731556594SKristen Carlson Accardi break; 102831556594SKristen Carlson Accardi case MEDIUM_POWER: 102931556594SKristen Carlson Accardi /* configure HBA to enter PARTIAL */ 103031556594SKristen Carlson Accardi asp = 0; 103131556594SKristen Carlson Accardi break; 103231556594SKristen Carlson Accardi default: 103331556594SKristen Carlson Accardi return -EINVAL; 103431556594SKristen Carlson Accardi } 103531556594SKristen Carlson Accardi 103631556594SKristen Carlson Accardi /* 103731556594SKristen Carlson Accardi * Disable interrupts on Phy Ready. This keeps us from 103831556594SKristen Carlson Accardi * getting woken up due to spurious phy ready interrupts 103931556594SKristen Carlson Accardi * TBD - Hot plug should be done via polling now, is 104031556594SKristen Carlson Accardi * that even supported? 104131556594SKristen Carlson Accardi */ 104231556594SKristen Carlson Accardi pp->intr_mask &= ~PORT_IRQ_PHYRDY; 104331556594SKristen Carlson Accardi writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 104431556594SKristen Carlson Accardi 104531556594SKristen Carlson Accardi /* 104631556594SKristen Carlson Accardi * Set a flag to indicate that we should ignore all PhyRdy 104731556594SKristen Carlson Accardi * state changes since these can happen now whenever we 104831556594SKristen Carlson Accardi * change link state 104931556594SKristen Carlson Accardi */ 105031556594SKristen Carlson Accardi hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; 105131556594SKristen Carlson Accardi 105231556594SKristen Carlson Accardi /* get the existing command bits */ 105331556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 105431556594SKristen Carlson Accardi 105531556594SKristen Carlson Accardi /* 105631556594SKristen Carlson Accardi * Set ASP based on Policy 105731556594SKristen Carlson Accardi */ 105831556594SKristen Carlson Accardi cmd |= asp; 105931556594SKristen Carlson Accardi 106031556594SKristen Carlson Accardi /* 106131556594SKristen Carlson Accardi * Setting this bit will instruct the HBA to aggressively 106231556594SKristen Carlson Accardi * enter a lower power link state when it's appropriate and 106331556594SKristen Carlson Accardi * based on the value set above for ASP 106431556594SKristen Carlson Accardi */ 106531556594SKristen Carlson Accardi cmd |= PORT_CMD_ALPE; 106631556594SKristen Carlson Accardi 106731556594SKristen Carlson Accardi /* write out new cmd value */ 106831556594SKristen Carlson Accardi writel(cmd, port_mmio + PORT_CMD); 106931556594SKristen Carlson Accardi cmd = readl(port_mmio + PORT_CMD); 107031556594SKristen Carlson Accardi 107131556594SKristen Carlson Accardi /* IPM bits should be set by libata-core */ 107231556594SKristen Carlson Accardi return 0; 107331556594SKristen Carlson Accardi } 107431556594SKristen Carlson Accardi 1075438ac6d5STejun Heo #ifdef CONFIG_PM 10764447d351STejun Heo static void ahci_power_down(struct ata_port *ap) 1077c6fd2807SJeff Garzik { 10784447d351STejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 10794447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1080c6fd2807SJeff Garzik u32 cmd, scontrol; 1081c6fd2807SJeff Garzik 10824447d351STejun Heo if (!(hpriv->cap & HOST_CAP_SSS)) 108307c53dacSTejun Heo return; 1084c6fd2807SJeff Garzik 108507c53dacSTejun Heo /* put device into listen mode, first set PxSCTL.DET to 0 */ 1086c6fd2807SJeff Garzik scontrol = readl(port_mmio + PORT_SCR_CTL); 1087c6fd2807SJeff Garzik scontrol &= ~0xf; 1088c6fd2807SJeff Garzik writel(scontrol, port_mmio + PORT_SCR_CTL); 1089c6fd2807SJeff Garzik 1090c6fd2807SJeff Garzik /* then set PxCMD.SUD to 0 */ 109107c53dacSTejun Heo cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 1092c6fd2807SJeff Garzik cmd &= ~PORT_CMD_SPIN_UP; 1093c6fd2807SJeff Garzik writel(cmd, port_mmio + PORT_CMD); 1094c6fd2807SJeff Garzik } 1095438ac6d5STejun Heo #endif 1096c6fd2807SJeff Garzik 1097df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap) 1098c6fd2807SJeff Garzik { 109918f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 110018f7ba4cSKristen Carlson Accardi struct ata_link *link; 110118f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 110218f7ba4cSKristen Carlson Accardi 1103c6fd2807SJeff Garzik /* enable FIS reception */ 11044447d351STejun Heo ahci_start_fis_rx(ap); 1105c6fd2807SJeff Garzik 1106c6fd2807SJeff Garzik /* enable DMA */ 11074447d351STejun Heo ahci_start_engine(ap); 110818f7ba4cSKristen Carlson Accardi 110918f7ba4cSKristen Carlson Accardi /* turn on LEDs */ 111018f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_EM) { 111118f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) { 111218f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[link->pmp]; 111318f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, emp->led_state, 4); 111418f7ba4cSKristen Carlson Accardi } 111518f7ba4cSKristen Carlson Accardi } 111618f7ba4cSKristen Carlson Accardi 111718f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_SW_ACTIVITY) 111818f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) 111918f7ba4cSKristen Carlson Accardi ahci_init_sw_activity(link); 112018f7ba4cSKristen Carlson Accardi 1121c6fd2807SJeff Garzik } 1122c6fd2807SJeff Garzik 11234447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg) 1124c6fd2807SJeff Garzik { 1125c6fd2807SJeff Garzik int rc; 1126c6fd2807SJeff Garzik 1127c6fd2807SJeff Garzik /* disable DMA */ 11284447d351STejun Heo rc = ahci_stop_engine(ap); 1129c6fd2807SJeff Garzik if (rc) { 1130c6fd2807SJeff Garzik *emsg = "failed to stop engine"; 1131c6fd2807SJeff Garzik return rc; 1132c6fd2807SJeff Garzik } 1133c6fd2807SJeff Garzik 1134c6fd2807SJeff Garzik /* disable FIS reception */ 11354447d351STejun Heo rc = ahci_stop_fis_rx(ap); 1136c6fd2807SJeff Garzik if (rc) { 1137c6fd2807SJeff Garzik *emsg = "failed stop FIS RX"; 1138c6fd2807SJeff Garzik return rc; 1139c6fd2807SJeff Garzik } 1140c6fd2807SJeff Garzik 1141c6fd2807SJeff Garzik return 0; 1142c6fd2807SJeff Garzik } 1143c6fd2807SJeff Garzik 11444447d351STejun Heo static int ahci_reset_controller(struct ata_host *host) 1145c6fd2807SJeff Garzik { 11464447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 114749f29090STejun Heo struct ahci_host_priv *hpriv = host->private_data; 11484447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 1149d447df14STejun Heo u32 tmp; 1150c6fd2807SJeff Garzik 11513cc3eb11SJeff Garzik /* we must be in AHCI mode, before using anything 11523cc3eb11SJeff Garzik * AHCI-specific, such as HOST_RESET. 11533cc3eb11SJeff Garzik */ 1154b710a1f4STejun Heo ahci_enable_ahci(mmio); 11553cc3eb11SJeff Garzik 11563cc3eb11SJeff Garzik /* global controller reset */ 1157a22e6444STejun Heo if (!ahci_skip_host_reset) { 1158b710a1f4STejun Heo tmp = readl(mmio + HOST_CTL); 1159c6fd2807SJeff Garzik if ((tmp & HOST_RESET) == 0) { 1160c6fd2807SJeff Garzik writel(tmp | HOST_RESET, mmio + HOST_CTL); 1161c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 1162c6fd2807SJeff Garzik } 1163c6fd2807SJeff Garzik 116424920c8aSZhang Rui /* 116524920c8aSZhang Rui * to perform host reset, OS should set HOST_RESET 116624920c8aSZhang Rui * and poll until this bit is read to be "0". 116724920c8aSZhang Rui * reset must complete within 1 second, or 1168c6fd2807SJeff Garzik * the hardware should be considered fried. 1169c6fd2807SJeff Garzik */ 117024920c8aSZhang Rui tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET, 117124920c8aSZhang Rui HOST_RESET, 10, 1000); 1172c6fd2807SJeff Garzik 1173c6fd2807SJeff Garzik if (tmp & HOST_RESET) { 11744447d351STejun Heo dev_printk(KERN_ERR, host->dev, 1175c6fd2807SJeff Garzik "controller reset failed (0x%x)\n", tmp); 1176c6fd2807SJeff Garzik return -EIO; 1177c6fd2807SJeff Garzik } 1178c6fd2807SJeff Garzik 117998fa4b60STejun Heo /* turn on AHCI mode */ 1180b710a1f4STejun Heo ahci_enable_ahci(mmio); 118198fa4b60STejun Heo 1182a22e6444STejun Heo /* Some registers might be cleared on reset. Restore 1183a22e6444STejun Heo * initial values. 1184a22e6444STejun Heo */ 11854447d351STejun Heo ahci_restore_initial_config(host); 1186a22e6444STejun Heo } else 1187a22e6444STejun Heo dev_printk(KERN_INFO, host->dev, 1188a22e6444STejun Heo "skipping global host reset\n"); 1189c6fd2807SJeff Garzik 1190c6fd2807SJeff Garzik if (pdev->vendor == PCI_VENDOR_ID_INTEL) { 1191c6fd2807SJeff Garzik u16 tmp16; 1192c6fd2807SJeff Garzik 1193c6fd2807SJeff Garzik /* configure PCS */ 1194c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x92, &tmp16); 119549f29090STejun Heo if ((tmp16 & hpriv->port_map) != hpriv->port_map) { 119649f29090STejun Heo tmp16 |= hpriv->port_map; 1197c6fd2807SJeff Garzik pci_write_config_word(pdev, 0x92, tmp16); 1198c6fd2807SJeff Garzik } 119949f29090STejun Heo } 1200c6fd2807SJeff Garzik 1201c6fd2807SJeff Garzik return 0; 1202c6fd2807SJeff Garzik } 1203c6fd2807SJeff Garzik 120418f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link) 120518f7ba4cSKristen Carlson Accardi { 120618f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 120718f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 120818f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 120918f7ba4cSKristen Carlson Accardi 121018f7ba4cSKristen Carlson Accardi if (!(link->flags & ATA_LFLAG_SW_ACTIVITY)) 121118f7ba4cSKristen Carlson Accardi return; 121218f7ba4cSKristen Carlson Accardi 121318f7ba4cSKristen Carlson Accardi emp->activity++; 121418f7ba4cSKristen Carlson Accardi if (!timer_pending(&emp->timer)) 121518f7ba4cSKristen Carlson Accardi mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10)); 121618f7ba4cSKristen Carlson Accardi } 121718f7ba4cSKristen Carlson Accardi 121818f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg) 121918f7ba4cSKristen Carlson Accardi { 122018f7ba4cSKristen Carlson Accardi struct ata_link *link = (struct ata_link *)arg; 122118f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 122218f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 122318f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 122418f7ba4cSKristen Carlson Accardi unsigned long led_message = emp->led_state; 122518f7ba4cSKristen Carlson Accardi u32 activity_led_state; 122618f7ba4cSKristen Carlson Accardi 122718f7ba4cSKristen Carlson Accardi led_message &= 0xffff0000; 122818f7ba4cSKristen Carlson Accardi led_message |= ap->port_no | (link->pmp << 8); 122918f7ba4cSKristen Carlson Accardi 123018f7ba4cSKristen Carlson Accardi /* check to see if we've had activity. If so, 123118f7ba4cSKristen Carlson Accardi * toggle state of LED and reset timer. If not, 123218f7ba4cSKristen Carlson Accardi * turn LED to desired idle state. 123318f7ba4cSKristen Carlson Accardi */ 123418f7ba4cSKristen Carlson Accardi if (emp->saved_activity != emp->activity) { 123518f7ba4cSKristen Carlson Accardi emp->saved_activity = emp->activity; 123618f7ba4cSKristen Carlson Accardi /* get the current LED state */ 123718f7ba4cSKristen Carlson Accardi activity_led_state = led_message & 0x00010000; 123818f7ba4cSKristen Carlson Accardi 123918f7ba4cSKristen Carlson Accardi if (activity_led_state) 124018f7ba4cSKristen Carlson Accardi activity_led_state = 0; 124118f7ba4cSKristen Carlson Accardi else 124218f7ba4cSKristen Carlson Accardi activity_led_state = 1; 124318f7ba4cSKristen Carlson Accardi 124418f7ba4cSKristen Carlson Accardi /* clear old state */ 124518f7ba4cSKristen Carlson Accardi led_message &= 0xfff8ffff; 124618f7ba4cSKristen Carlson Accardi 124718f7ba4cSKristen Carlson Accardi /* toggle state */ 124818f7ba4cSKristen Carlson Accardi led_message |= (activity_led_state << 16); 124918f7ba4cSKristen Carlson Accardi mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100)); 125018f7ba4cSKristen Carlson Accardi } else { 125118f7ba4cSKristen Carlson Accardi /* switch to idle */ 125218f7ba4cSKristen Carlson Accardi led_message &= 0xfff8ffff; 125318f7ba4cSKristen Carlson Accardi if (emp->blink_policy == BLINK_OFF) 125418f7ba4cSKristen Carlson Accardi led_message |= (1 << 16); 125518f7ba4cSKristen Carlson Accardi } 125618f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, led_message, 4); 125718f7ba4cSKristen Carlson Accardi } 125818f7ba4cSKristen Carlson Accardi 125918f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link) 126018f7ba4cSKristen Carlson Accardi { 126118f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 126218f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 126318f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 126418f7ba4cSKristen Carlson Accardi 126518f7ba4cSKristen Carlson Accardi /* init activity stats, setup timer */ 126618f7ba4cSKristen Carlson Accardi emp->saved_activity = emp->activity = 0; 126718f7ba4cSKristen Carlson Accardi setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link); 126818f7ba4cSKristen Carlson Accardi 126918f7ba4cSKristen Carlson Accardi /* check our blink policy and set flag for link if it's enabled */ 127018f7ba4cSKristen Carlson Accardi if (emp->blink_policy) 127118f7ba4cSKristen Carlson Accardi link->flags |= ATA_LFLAG_SW_ACTIVITY; 127218f7ba4cSKristen Carlson Accardi } 127318f7ba4cSKristen Carlson Accardi 127418f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host) 127518f7ba4cSKristen Carlson Accardi { 127618f7ba4cSKristen Carlson Accardi void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 127718f7ba4cSKristen Carlson Accardi u32 em_ctl; 127818f7ba4cSKristen Carlson Accardi 127918f7ba4cSKristen Carlson Accardi em_ctl = readl(mmio + HOST_EM_CTL); 128018f7ba4cSKristen Carlson Accardi if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST)) 128118f7ba4cSKristen Carlson Accardi return -EINVAL; 128218f7ba4cSKristen Carlson Accardi 128318f7ba4cSKristen Carlson Accardi writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL); 128418f7ba4cSKristen Carlson Accardi return 0; 128518f7ba4cSKristen Carlson Accardi } 128618f7ba4cSKristen Carlson Accardi 128718f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, 128818f7ba4cSKristen Carlson Accardi ssize_t size) 128918f7ba4cSKristen Carlson Accardi { 129018f7ba4cSKristen Carlson Accardi struct ahci_host_priv *hpriv = ap->host->private_data; 129118f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 129218f7ba4cSKristen Carlson Accardi void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 129318f7ba4cSKristen Carlson Accardi u32 em_ctl; 129418f7ba4cSKristen Carlson Accardi u32 message[] = {0, 0}; 129593082f0bSLinus Torvalds unsigned long flags; 129618f7ba4cSKristen Carlson Accardi int pmp; 129718f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 129818f7ba4cSKristen Carlson Accardi 129918f7ba4cSKristen Carlson Accardi /* get the slot number from the message */ 130018f7ba4cSKristen Carlson Accardi pmp = (state & 0x0000ff00) >> 8; 130118f7ba4cSKristen Carlson Accardi if (pmp < MAX_SLOTS) 130218f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[pmp]; 130318f7ba4cSKristen Carlson Accardi else 130418f7ba4cSKristen Carlson Accardi return -EINVAL; 130518f7ba4cSKristen Carlson Accardi 130618f7ba4cSKristen Carlson Accardi spin_lock_irqsave(ap->lock, flags); 130718f7ba4cSKristen Carlson Accardi 130818f7ba4cSKristen Carlson Accardi /* 130918f7ba4cSKristen Carlson Accardi * if we are still busy transmitting a previous message, 131018f7ba4cSKristen Carlson Accardi * do not allow 131118f7ba4cSKristen Carlson Accardi */ 131218f7ba4cSKristen Carlson Accardi em_ctl = readl(mmio + HOST_EM_CTL); 131318f7ba4cSKristen Carlson Accardi if (em_ctl & EM_CTL_TM) { 131418f7ba4cSKristen Carlson Accardi spin_unlock_irqrestore(ap->lock, flags); 131518f7ba4cSKristen Carlson Accardi return -EINVAL; 131618f7ba4cSKristen Carlson Accardi } 131718f7ba4cSKristen Carlson Accardi 131818f7ba4cSKristen Carlson Accardi /* 131918f7ba4cSKristen Carlson Accardi * create message header - this is all zero except for 132018f7ba4cSKristen Carlson Accardi * the message size, which is 4 bytes. 132118f7ba4cSKristen Carlson Accardi */ 132218f7ba4cSKristen Carlson Accardi message[0] |= (4 << 8); 132318f7ba4cSKristen Carlson Accardi 132418f7ba4cSKristen Carlson Accardi /* ignore 0:4 of byte zero, fill in port info yourself */ 132518f7ba4cSKristen Carlson Accardi message[1] = ((state & 0xfffffff0) | ap->port_no); 132618f7ba4cSKristen Carlson Accardi 132718f7ba4cSKristen Carlson Accardi /* write message to EM_LOC */ 132818f7ba4cSKristen Carlson Accardi writel(message[0], mmio + hpriv->em_loc); 132918f7ba4cSKristen Carlson Accardi writel(message[1], mmio + hpriv->em_loc+4); 133018f7ba4cSKristen Carlson Accardi 133118f7ba4cSKristen Carlson Accardi /* save off new led state for port/slot */ 133218f7ba4cSKristen Carlson Accardi emp->led_state = message[1]; 133318f7ba4cSKristen Carlson Accardi 133418f7ba4cSKristen Carlson Accardi /* 133518f7ba4cSKristen Carlson Accardi * tell hardware to transmit the message 133618f7ba4cSKristen Carlson Accardi */ 133718f7ba4cSKristen Carlson Accardi writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); 133818f7ba4cSKristen Carlson Accardi 133918f7ba4cSKristen Carlson Accardi spin_unlock_irqrestore(ap->lock, flags); 134018f7ba4cSKristen Carlson Accardi return size; 134118f7ba4cSKristen Carlson Accardi } 134218f7ba4cSKristen Carlson Accardi 134318f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf) 134418f7ba4cSKristen Carlson Accardi { 134518f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 134618f7ba4cSKristen Carlson Accardi struct ata_link *link; 134718f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 134818f7ba4cSKristen Carlson Accardi int rc = 0; 134918f7ba4cSKristen Carlson Accardi 135018f7ba4cSKristen Carlson Accardi ata_port_for_each_link(link, ap) { 135118f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[link->pmp]; 135218f7ba4cSKristen Carlson Accardi rc += sprintf(buf, "%lx\n", emp->led_state); 135318f7ba4cSKristen Carlson Accardi } 135418f7ba4cSKristen Carlson Accardi return rc; 135518f7ba4cSKristen Carlson Accardi } 135618f7ba4cSKristen Carlson Accardi 135718f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, 135818f7ba4cSKristen Carlson Accardi size_t size) 135918f7ba4cSKristen Carlson Accardi { 136018f7ba4cSKristen Carlson Accardi int state; 136118f7ba4cSKristen Carlson Accardi int pmp; 136218f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 136318f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp; 136418f7ba4cSKristen Carlson Accardi 136518f7ba4cSKristen Carlson Accardi state = simple_strtoul(buf, NULL, 0); 136618f7ba4cSKristen Carlson Accardi 136718f7ba4cSKristen Carlson Accardi /* get the slot number from the message */ 136818f7ba4cSKristen Carlson Accardi pmp = (state & 0x0000ff00) >> 8; 136918f7ba4cSKristen Carlson Accardi if (pmp < MAX_SLOTS) 137018f7ba4cSKristen Carlson Accardi emp = &pp->em_priv[pmp]; 137118f7ba4cSKristen Carlson Accardi else 137218f7ba4cSKristen Carlson Accardi return -EINVAL; 137318f7ba4cSKristen Carlson Accardi 137418f7ba4cSKristen Carlson Accardi /* mask off the activity bits if we are in sw_activity 137518f7ba4cSKristen Carlson Accardi * mode, user should turn off sw_activity before setting 137618f7ba4cSKristen Carlson Accardi * activity led through em_message 137718f7ba4cSKristen Carlson Accardi */ 137818f7ba4cSKristen Carlson Accardi if (emp->blink_policy) 137918f7ba4cSKristen Carlson Accardi state &= 0xfff8ffff; 138018f7ba4cSKristen Carlson Accardi 138118f7ba4cSKristen Carlson Accardi return ahci_transmit_led_message(ap, state, size); 138218f7ba4cSKristen Carlson Accardi } 138318f7ba4cSKristen Carlson Accardi 138418f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val) 138518f7ba4cSKristen Carlson Accardi { 138618f7ba4cSKristen Carlson Accardi struct ata_link *link = dev->link; 138718f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 138818f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 138918f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 139018f7ba4cSKristen Carlson Accardi u32 port_led_state = emp->led_state; 139118f7ba4cSKristen Carlson Accardi 139218f7ba4cSKristen Carlson Accardi /* save the desired Activity LED behavior */ 139318f7ba4cSKristen Carlson Accardi if (val == OFF) { 139418f7ba4cSKristen Carlson Accardi /* clear LFLAG */ 139518f7ba4cSKristen Carlson Accardi link->flags &= ~(ATA_LFLAG_SW_ACTIVITY); 139618f7ba4cSKristen Carlson Accardi 139718f7ba4cSKristen Carlson Accardi /* set the LED to OFF */ 139818f7ba4cSKristen Carlson Accardi port_led_state &= 0xfff80000; 139918f7ba4cSKristen Carlson Accardi port_led_state |= (ap->port_no | (link->pmp << 8)); 140018f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, port_led_state, 4); 140118f7ba4cSKristen Carlson Accardi } else { 140218f7ba4cSKristen Carlson Accardi link->flags |= ATA_LFLAG_SW_ACTIVITY; 140318f7ba4cSKristen Carlson Accardi if (val == BLINK_OFF) { 140418f7ba4cSKristen Carlson Accardi /* set LED to ON for idle */ 140518f7ba4cSKristen Carlson Accardi port_led_state &= 0xfff80000; 140618f7ba4cSKristen Carlson Accardi port_led_state |= (ap->port_no | (link->pmp << 8)); 140718f7ba4cSKristen Carlson Accardi port_led_state |= 0x00010000; /* check this */ 140818f7ba4cSKristen Carlson Accardi ahci_transmit_led_message(ap, port_led_state, 4); 140918f7ba4cSKristen Carlson Accardi } 141018f7ba4cSKristen Carlson Accardi } 141118f7ba4cSKristen Carlson Accardi emp->blink_policy = val; 141218f7ba4cSKristen Carlson Accardi return 0; 141318f7ba4cSKristen Carlson Accardi } 141418f7ba4cSKristen Carlson Accardi 141518f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) 141618f7ba4cSKristen Carlson Accardi { 141718f7ba4cSKristen Carlson Accardi struct ata_link *link = dev->link; 141818f7ba4cSKristen Carlson Accardi struct ata_port *ap = link->ap; 141918f7ba4cSKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 142018f7ba4cSKristen Carlson Accardi struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; 142118f7ba4cSKristen Carlson Accardi 142218f7ba4cSKristen Carlson Accardi /* display the saved value of activity behavior for this 142318f7ba4cSKristen Carlson Accardi * disk. 142418f7ba4cSKristen Carlson Accardi */ 142518f7ba4cSKristen Carlson Accardi return sprintf(buf, "%d\n", emp->blink_policy); 142618f7ba4cSKristen Carlson Accardi } 142718f7ba4cSKristen Carlson Accardi 14282bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, 14292bcd866bSJeff Garzik int port_no, void __iomem *mmio, 14302bcd866bSJeff Garzik void __iomem *port_mmio) 1431c6fd2807SJeff Garzik { 1432c6fd2807SJeff Garzik const char *emsg = NULL; 14332bcd866bSJeff Garzik int rc; 14342bcd866bSJeff Garzik u32 tmp; 1435c6fd2807SJeff Garzik 1436c6fd2807SJeff Garzik /* make sure port is not active */ 14374447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 1438c6fd2807SJeff Garzik if (rc) 1439c6fd2807SJeff Garzik dev_printk(KERN_WARNING, &pdev->dev, 1440c6fd2807SJeff Garzik "%s (%d)\n", emsg, rc); 1441c6fd2807SJeff Garzik 1442c6fd2807SJeff Garzik /* clear SError */ 1443c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SCR_ERR); 1444c6fd2807SJeff Garzik VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 1445c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_SCR_ERR); 1446c6fd2807SJeff Garzik 1447c6fd2807SJeff Garzik /* clear port IRQ */ 1448c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1449c6fd2807SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1450c6fd2807SJeff Garzik if (tmp) 1451c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1452c6fd2807SJeff Garzik 14532bcd866bSJeff Garzik writel(1 << port_no, mmio + HOST_IRQ_STAT); 14542bcd866bSJeff Garzik } 14552bcd866bSJeff Garzik 14562bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host) 14572bcd866bSJeff Garzik { 1458417a1a6dSTejun Heo struct ahci_host_priv *hpriv = host->private_data; 14592bcd866bSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 14602bcd866bSJeff Garzik void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 14612bcd866bSJeff Garzik int i; 1462cd70c266SJeff Garzik void __iomem *port_mmio; 14632bcd866bSJeff Garzik u32 tmp; 1464c40e7cb8SJose Alberto Reguero int mv; 14652bcd866bSJeff Garzik 1466417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_MV_PATA) { 1467c40e7cb8SJose Alberto Reguero if (pdev->device == 0x6121) 1468c40e7cb8SJose Alberto Reguero mv = 2; 1469c40e7cb8SJose Alberto Reguero else 1470c40e7cb8SJose Alberto Reguero mv = 4; 1471c40e7cb8SJose Alberto Reguero port_mmio = __ahci_port_base(host, mv); 1472cd70c266SJeff Garzik 1473cd70c266SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 1474cd70c266SJeff Garzik 1475cd70c266SJeff Garzik /* clear port IRQ */ 1476cd70c266SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 1477cd70c266SJeff Garzik VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1478cd70c266SJeff Garzik if (tmp) 1479cd70c266SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 1480cd70c266SJeff Garzik } 1481cd70c266SJeff Garzik 14822bcd866bSJeff Garzik for (i = 0; i < host->n_ports; i++) { 14832bcd866bSJeff Garzik struct ata_port *ap = host->ports[i]; 14842bcd866bSJeff Garzik 1485cd70c266SJeff Garzik port_mmio = ahci_port_base(ap); 14862bcd866bSJeff Garzik if (ata_port_is_dummy(ap)) 14872bcd866bSJeff Garzik continue; 14882bcd866bSJeff Garzik 14892bcd866bSJeff Garzik ahci_port_init(pdev, ap, i, mmio, port_mmio); 1490c6fd2807SJeff Garzik } 1491c6fd2807SJeff Garzik 1492c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1493c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1494c6fd2807SJeff Garzik writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); 1495c6fd2807SJeff Garzik tmp = readl(mmio + HOST_CTL); 1496c6fd2807SJeff Garzik VPRINTK("HOST_CTL 0x%x\n", tmp); 1497c6fd2807SJeff Garzik } 1498c6fd2807SJeff Garzik 1499a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev) 1500a878539eSJeff Garzik { 1501a878539eSJeff Garzik struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; 1502a878539eSJeff Garzik 15034cde32fcSJeff Garzik if (hpriv->flags & AHCI_HFLAG_SECT255) { 1504a878539eSJeff Garzik dev->max_sectors = 255; 15054cde32fcSJeff Garzik ata_dev_printk(dev, KERN_INFO, 15064cde32fcSJeff Garzik "SB600 AHCI: limiting to 255 sectors per cmd\n"); 15074cde32fcSJeff Garzik } 1508a878539eSJeff Garzik } 1509a878539eSJeff Garzik 1510c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap) 1511c6fd2807SJeff Garzik { 15124447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1513c6fd2807SJeff Garzik struct ata_taskfile tf; 1514c6fd2807SJeff Garzik u32 tmp; 1515c6fd2807SJeff Garzik 1516c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_SIG); 1517c6fd2807SJeff Garzik tf.lbah = (tmp >> 24) & 0xff; 1518c6fd2807SJeff Garzik tf.lbam = (tmp >> 16) & 0xff; 1519c6fd2807SJeff Garzik tf.lbal = (tmp >> 8) & 0xff; 1520c6fd2807SJeff Garzik tf.nsect = (tmp) & 0xff; 1521c6fd2807SJeff Garzik 1522c6fd2807SJeff Garzik return ata_dev_classify(&tf); 1523c6fd2807SJeff Garzik } 1524c6fd2807SJeff Garzik 1525c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, 1526c6fd2807SJeff Garzik u32 opts) 1527c6fd2807SJeff Garzik { 1528c6fd2807SJeff Garzik dma_addr_t cmd_tbl_dma; 1529c6fd2807SJeff Garzik 1530c6fd2807SJeff Garzik cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; 1531c6fd2807SJeff Garzik 1532c6fd2807SJeff Garzik pp->cmd_slot[tag].opts = cpu_to_le32(opts); 1533c6fd2807SJeff Garzik pp->cmd_slot[tag].status = 0; 1534c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); 1535c6fd2807SJeff Garzik pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); 1536c6fd2807SJeff Garzik } 1537c6fd2807SJeff Garzik 1538d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart) 1539c6fd2807SJeff Garzik { 1540350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1541cca3974eSJeff Garzik struct ahci_host_priv *hpriv = ap->host->private_data; 1542520d06f9STejun Heo u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1543c6fd2807SJeff Garzik u32 tmp; 1544d2e75dffSTejun Heo int busy, rc; 1545c6fd2807SJeff Garzik 1546d2e75dffSTejun Heo /* do we need to kick the port? */ 1547520d06f9STejun Heo busy = status & (ATA_BUSY | ATA_DRQ); 1548d2e75dffSTejun Heo if (!busy && !force_restart) 1549d2e75dffSTejun Heo return 0; 1550c6fd2807SJeff Garzik 1551d2e75dffSTejun Heo /* stop engine */ 1552d2e75dffSTejun Heo rc = ahci_stop_engine(ap); 1553d2e75dffSTejun Heo if (rc) 1554d2e75dffSTejun Heo goto out_restart; 1555d2e75dffSTejun Heo 1556d2e75dffSTejun Heo /* need to do CLO? */ 1557d2e75dffSTejun Heo if (!busy) { 1558d2e75dffSTejun Heo rc = 0; 1559d2e75dffSTejun Heo goto out_restart; 1560d2e75dffSTejun Heo } 1561d2e75dffSTejun Heo 1562d2e75dffSTejun Heo if (!(hpriv->cap & HOST_CAP_CLO)) { 1563d2e75dffSTejun Heo rc = -EOPNOTSUPP; 1564d2e75dffSTejun Heo goto out_restart; 1565d2e75dffSTejun Heo } 1566d2e75dffSTejun Heo 1567d2e75dffSTejun Heo /* perform CLO */ 1568c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_CMD); 1569c6fd2807SJeff Garzik tmp |= PORT_CMD_CLO; 1570c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_CMD); 1571c6fd2807SJeff Garzik 1572d2e75dffSTejun Heo rc = 0; 1573c6fd2807SJeff Garzik tmp = ata_wait_register(port_mmio + PORT_CMD, 1574c6fd2807SJeff Garzik PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 1575c6fd2807SJeff Garzik if (tmp & PORT_CMD_CLO) 1576d2e75dffSTejun Heo rc = -EIO; 1577c6fd2807SJeff Garzik 1578d2e75dffSTejun Heo /* restart engine */ 1579d2e75dffSTejun Heo out_restart: 1580d2e75dffSTejun Heo ahci_start_engine(ap); 1581d2e75dffSTejun Heo return rc; 1582c6fd2807SJeff Garzik } 1583c6fd2807SJeff Garzik 158491c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, 158591c4a2e0STejun Heo struct ata_taskfile *tf, int is_cmd, u16 flags, 158691c4a2e0STejun Heo unsigned long timeout_msec) 158791c4a2e0STejun Heo { 158891c4a2e0STejun Heo const u32 cmd_fis_len = 5; /* five dwords */ 158991c4a2e0STejun Heo struct ahci_port_priv *pp = ap->private_data; 159091c4a2e0STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 159191c4a2e0STejun Heo u8 *fis = pp->cmd_tbl; 159291c4a2e0STejun Heo u32 tmp; 159391c4a2e0STejun Heo 159491c4a2e0STejun Heo /* prep the command */ 159591c4a2e0STejun Heo ata_tf_to_fis(tf, pmp, is_cmd, fis); 159691c4a2e0STejun Heo ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); 159791c4a2e0STejun Heo 159891c4a2e0STejun Heo /* issue & wait */ 159991c4a2e0STejun Heo writel(1, port_mmio + PORT_CMD_ISSUE); 160091c4a2e0STejun Heo 160191c4a2e0STejun Heo if (timeout_msec) { 160291c4a2e0STejun Heo tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 160391c4a2e0STejun Heo 1, timeout_msec); 160491c4a2e0STejun Heo if (tmp & 0x1) { 160591c4a2e0STejun Heo ahci_kick_engine(ap, 1); 160691c4a2e0STejun Heo return -EBUSY; 160791c4a2e0STejun Heo } 160891c4a2e0STejun Heo } else 160991c4a2e0STejun Heo readl(port_mmio + PORT_CMD_ISSUE); /* flush */ 161091c4a2e0STejun Heo 161191c4a2e0STejun Heo return 0; 161291c4a2e0STejun Heo } 161391c4a2e0STejun Heo 1614bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class, 1615bd17243aSShane Huang int pmp, unsigned long deadline, 1616bd17243aSShane Huang int (*check_ready)(struct ata_link *link)) 1617c6fd2807SJeff Garzik { 1618cc0680a5STejun Heo struct ata_port *ap = link->ap; 1619c6fd2807SJeff Garzik const char *reason = NULL; 16202cbb79ebSTejun Heo unsigned long now, msecs; 1621c6fd2807SJeff Garzik struct ata_taskfile tf; 1622c6fd2807SJeff Garzik int rc; 1623c6fd2807SJeff Garzik 1624c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1625c6fd2807SJeff Garzik 1626c6fd2807SJeff Garzik /* prepare for SRST (AHCI-1.1 10.4.1) */ 1627d2e75dffSTejun Heo rc = ahci_kick_engine(ap, 1); 1628994056d7STejun Heo if (rc && rc != -EOPNOTSUPP) 1629cc0680a5STejun Heo ata_link_printk(link, KERN_WARNING, 1630994056d7STejun Heo "failed to reset engine (errno=%d)\n", rc); 1631c6fd2807SJeff Garzik 1632cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1633c6fd2807SJeff Garzik 1634c6fd2807SJeff Garzik /* issue the first D2H Register FIS */ 16352cbb79ebSTejun Heo msecs = 0; 16362cbb79ebSTejun Heo now = jiffies; 16372cbb79ebSTejun Heo if (time_after(now, deadline)) 16382cbb79ebSTejun Heo msecs = jiffies_to_msecs(deadline - now); 16392cbb79ebSTejun Heo 1640c6fd2807SJeff Garzik tf.ctl |= ATA_SRST; 1641a9cf5e85STejun Heo if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, 164291c4a2e0STejun Heo AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { 1643c6fd2807SJeff Garzik rc = -EIO; 1644c6fd2807SJeff Garzik reason = "1st FIS failed"; 1645c6fd2807SJeff Garzik goto fail; 1646c6fd2807SJeff Garzik } 1647c6fd2807SJeff Garzik 1648c6fd2807SJeff Garzik /* spec says at least 5us, but be generous and sleep for 1ms */ 1649c6fd2807SJeff Garzik msleep(1); 1650c6fd2807SJeff Garzik 1651c6fd2807SJeff Garzik /* issue the second D2H Register FIS */ 1652c6fd2807SJeff Garzik tf.ctl &= ~ATA_SRST; 1653a9cf5e85STejun Heo ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1654c6fd2807SJeff Garzik 1655705e76beSTejun Heo /* wait for link to become ready */ 1656bd17243aSShane Huang rc = ata_wait_after_reset(link, deadline, check_ready); 16579b89391cSTejun Heo /* link occupied, -ENODEV too is an error */ 16589b89391cSTejun Heo if (rc) { 1659c6fd2807SJeff Garzik reason = "device not ready"; 1660c6fd2807SJeff Garzik goto fail; 1661c6fd2807SJeff Garzik } 1662c6fd2807SJeff Garzik *class = ahci_dev_classify(ap); 1663c6fd2807SJeff Garzik 1664c6fd2807SJeff Garzik DPRINTK("EXIT, class=%u\n", *class); 1665c6fd2807SJeff Garzik return 0; 1666c6fd2807SJeff Garzik 1667c6fd2807SJeff Garzik fail: 1668cc0680a5STejun Heo ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); 1669c6fd2807SJeff Garzik return rc; 1670c6fd2807SJeff Garzik } 1671c6fd2807SJeff Garzik 1672bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link) 1673bd17243aSShane Huang { 1674bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(link->ap); 1675bd17243aSShane Huang u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1676bd17243aSShane Huang 1677bd17243aSShane Huang return ata_check_ready(status); 1678bd17243aSShane Huang } 1679bd17243aSShane Huang 1680bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class, 1681bd17243aSShane Huang unsigned long deadline) 1682bd17243aSShane Huang { 1683bd17243aSShane Huang int pmp = sata_srst_pmp(link); 1684bd17243aSShane Huang 1685bd17243aSShane Huang DPRINTK("ENTER\n"); 1686bd17243aSShane Huang 1687bd17243aSShane Huang return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); 1688bd17243aSShane Huang } 1689bd17243aSShane Huang 1690bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link) 1691bd17243aSShane Huang { 1692bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(link->ap); 1693bd17243aSShane Huang u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; 1694bd17243aSShane Huang u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); 1695bd17243aSShane Huang 1696bd17243aSShane Huang /* 1697bd17243aSShane Huang * There is no need to check TFDATA if BAD PMP is found due to HW bug, 1698bd17243aSShane Huang * which can save timeout delay. 1699bd17243aSShane Huang */ 1700bd17243aSShane Huang if (irq_status & PORT_IRQ_BAD_PMP) 1701bd17243aSShane Huang return -EIO; 1702bd17243aSShane Huang 1703bd17243aSShane Huang return ata_check_ready(status); 1704bd17243aSShane Huang } 1705bd17243aSShane Huang 1706bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, 1707bd17243aSShane Huang unsigned long deadline) 1708bd17243aSShane Huang { 1709bd17243aSShane Huang struct ata_port *ap = link->ap; 1710bd17243aSShane Huang void __iomem *port_mmio = ahci_port_base(ap); 1711bd17243aSShane Huang int pmp = sata_srst_pmp(link); 1712bd17243aSShane Huang int rc; 1713bd17243aSShane Huang u32 irq_sts; 1714bd17243aSShane Huang 1715bd17243aSShane Huang DPRINTK("ENTER\n"); 1716bd17243aSShane Huang 1717bd17243aSShane Huang rc = ahci_do_softreset(link, class, pmp, deadline, 1718bd17243aSShane Huang ahci_sb600_check_ready); 1719bd17243aSShane Huang 1720bd17243aSShane Huang /* 1721bd17243aSShane Huang * Soft reset fails on some ATI chips with IPMS set when PMP 1722bd17243aSShane Huang * is enabled but SATA HDD/ODD is connected to SATA port, 1723bd17243aSShane Huang * do soft reset again to port 0. 1724bd17243aSShane Huang */ 1725bd17243aSShane Huang if (rc == -EIO) { 1726bd17243aSShane Huang irq_sts = readl(port_mmio + PORT_IRQ_STAT); 1727bd17243aSShane Huang if (irq_sts & PORT_IRQ_BAD_PMP) { 1728bd17243aSShane Huang ata_link_printk(link, KERN_WARNING, 1729bd17243aSShane Huang "failed due to HW bug, retry pmp=0\n"); 1730bd17243aSShane Huang rc = ahci_do_softreset(link, class, 0, deadline, 1731bd17243aSShane Huang ahci_check_ready); 1732bd17243aSShane Huang } 1733bd17243aSShane Huang } 1734bd17243aSShane Huang 1735bd17243aSShane Huang return rc; 1736bd17243aSShane Huang } 1737bd17243aSShane Huang 1738cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1739d4b2bab4STejun Heo unsigned long deadline) 1740c6fd2807SJeff Garzik { 17419dadd45bSTejun Heo const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); 1742cc0680a5STejun Heo struct ata_port *ap = link->ap; 1743c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1744c6fd2807SJeff Garzik u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1745c6fd2807SJeff Garzik struct ata_taskfile tf; 17469dadd45bSTejun Heo bool online; 1747c6fd2807SJeff Garzik int rc; 1748c6fd2807SJeff Garzik 1749c6fd2807SJeff Garzik DPRINTK("ENTER\n"); 1750c6fd2807SJeff Garzik 17514447d351STejun Heo ahci_stop_engine(ap); 1752c6fd2807SJeff Garzik 1753c6fd2807SJeff Garzik /* clear D2H reception area to properly wait for D2H FIS */ 1754cc0680a5STejun Heo ata_tf_init(link->device, &tf); 1755dfd7a3dbSTejun Heo tf.command = 0x80; 17569977126cSTejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1757c6fd2807SJeff Garzik 17589dadd45bSTejun Heo rc = sata_link_hardreset(link, timing, deadline, &online, 17599dadd45bSTejun Heo ahci_check_ready); 1760c6fd2807SJeff Garzik 17614447d351STejun Heo ahci_start_engine(ap); 1762c6fd2807SJeff Garzik 17639dadd45bSTejun Heo if (online) 17649dadd45bSTejun Heo *class = ahci_dev_classify(ap); 1765c6fd2807SJeff Garzik 1766c6fd2807SJeff Garzik DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1767c6fd2807SJeff Garzik return rc; 1768c6fd2807SJeff Garzik } 1769c6fd2807SJeff Garzik 1770cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 1771d4b2bab4STejun Heo unsigned long deadline) 1772ad616ffbSTejun Heo { 1773cc0680a5STejun Heo struct ata_port *ap = link->ap; 17749dadd45bSTejun Heo bool online; 1775ad616ffbSTejun Heo int rc; 1776ad616ffbSTejun Heo 1777ad616ffbSTejun Heo DPRINTK("ENTER\n"); 1778ad616ffbSTejun Heo 17794447d351STejun Heo ahci_stop_engine(ap); 1780ad616ffbSTejun Heo 1781cc0680a5STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 17829dadd45bSTejun Heo deadline, &online, NULL); 1783ad616ffbSTejun Heo 17844447d351STejun Heo ahci_start_engine(ap); 1785ad616ffbSTejun Heo 1786ad616ffbSTejun Heo DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); 1787ad616ffbSTejun Heo 1788ad616ffbSTejun Heo /* vt8251 doesn't clear BSY on signature FIS reception, 1789ad616ffbSTejun Heo * request follow-up softreset. 1790ad616ffbSTejun Heo */ 17919dadd45bSTejun Heo return online ? -EAGAIN : rc; 1792ad616ffbSTejun Heo } 1793ad616ffbSTejun Heo 1794edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 1795edc93052STejun Heo unsigned long deadline) 1796edc93052STejun Heo { 1797edc93052STejun Heo struct ata_port *ap = link->ap; 1798edc93052STejun Heo struct ahci_port_priv *pp = ap->private_data; 1799edc93052STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1800edc93052STejun Heo struct ata_taskfile tf; 18019dadd45bSTejun Heo bool online; 1802edc93052STejun Heo int rc; 1803edc93052STejun Heo 1804edc93052STejun Heo ahci_stop_engine(ap); 1805edc93052STejun Heo 1806edc93052STejun Heo /* clear D2H reception area to properly wait for D2H FIS */ 1807edc93052STejun Heo ata_tf_init(link->device, &tf); 1808edc93052STejun Heo tf.command = 0x80; 1809edc93052STejun Heo ata_tf_to_fis(&tf, 0, 0, d2h_fis); 1810edc93052STejun Heo 1811edc93052STejun Heo rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), 18129dadd45bSTejun Heo deadline, &online, NULL); 1813edc93052STejun Heo 1814edc93052STejun Heo ahci_start_engine(ap); 1815edc93052STejun Heo 1816edc93052STejun Heo /* The pseudo configuration device on SIMG4726 attached to 1817edc93052STejun Heo * ASUS P5W-DH Deluxe doesn't send signature FIS after 1818edc93052STejun Heo * hardreset if no device is attached to the first downstream 1819edc93052STejun Heo * port && the pseudo device locks up on SRST w/ PMP==0. To 1820edc93052STejun Heo * work around this, wait for !BSY only briefly. If BSY isn't 1821edc93052STejun Heo * cleared, perform CLO and proceed to IDENTIFY (achieved by 1822edc93052STejun Heo * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA). 1823edc93052STejun Heo * 1824edc93052STejun Heo * Wait for two seconds. Devices attached to downstream port 1825edc93052STejun Heo * which can't process the following IDENTIFY after this will 1826edc93052STejun Heo * have to be reset again. For most cases, this should 1827edc93052STejun Heo * suffice while making probing snappish enough. 1828edc93052STejun Heo */ 18299dadd45bSTejun Heo if (online) { 18309dadd45bSTejun Heo rc = ata_wait_after_reset(link, jiffies + 2 * HZ, 18319dadd45bSTejun Heo ahci_check_ready); 1832edc93052STejun Heo if (rc) 1833edc93052STejun Heo ahci_kick_engine(ap, 0); 18349dadd45bSTejun Heo } 18359dadd45bSTejun Heo return rc; 1836edc93052STejun Heo } 1837edc93052STejun Heo 1838cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class) 1839c6fd2807SJeff Garzik { 1840cc0680a5STejun Heo struct ata_port *ap = link->ap; 18414447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 1842c6fd2807SJeff Garzik u32 new_tmp, tmp; 1843c6fd2807SJeff Garzik 1844203c75b8STejun Heo ata_std_postreset(link, class); 1845c6fd2807SJeff Garzik 1846c6fd2807SJeff Garzik /* Make sure port's ATAPI bit is set appropriately */ 1847c6fd2807SJeff Garzik new_tmp = tmp = readl(port_mmio + PORT_CMD); 1848c6fd2807SJeff Garzik if (*class == ATA_DEV_ATAPI) 1849c6fd2807SJeff Garzik new_tmp |= PORT_CMD_ATAPI; 1850c6fd2807SJeff Garzik else 1851c6fd2807SJeff Garzik new_tmp &= ~PORT_CMD_ATAPI; 1852c6fd2807SJeff Garzik if (new_tmp != tmp) { 1853c6fd2807SJeff Garzik writel(new_tmp, port_mmio + PORT_CMD); 1854c6fd2807SJeff Garzik readl(port_mmio + PORT_CMD); /* flush */ 1855c6fd2807SJeff Garzik } 1856c6fd2807SJeff Garzik } 1857c6fd2807SJeff Garzik 1858c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) 1859c6fd2807SJeff Garzik { 1860c6fd2807SJeff Garzik struct scatterlist *sg; 1861ff2aeb1eSTejun Heo struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; 1862ff2aeb1eSTejun Heo unsigned int si; 1863c6fd2807SJeff Garzik 1864c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 1865c6fd2807SJeff Garzik 1866c6fd2807SJeff Garzik /* 1867c6fd2807SJeff Garzik * Next, the S/G list. 1868c6fd2807SJeff Garzik */ 1869ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) { 1870c6fd2807SJeff Garzik dma_addr_t addr = sg_dma_address(sg); 1871c6fd2807SJeff Garzik u32 sg_len = sg_dma_len(sg); 1872c6fd2807SJeff Garzik 1873ff2aeb1eSTejun Heo ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); 1874ff2aeb1eSTejun Heo ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); 1875ff2aeb1eSTejun Heo ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); 1876c6fd2807SJeff Garzik } 1877c6fd2807SJeff Garzik 1878ff2aeb1eSTejun Heo return si; 1879c6fd2807SJeff Garzik } 1880c6fd2807SJeff Garzik 1881c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc) 1882c6fd2807SJeff Garzik { 1883c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 1884c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 1885405e66b3STejun Heo int is_atapi = ata_is_atapi(qc->tf.protocol); 1886c6fd2807SJeff Garzik void *cmd_tbl; 1887c6fd2807SJeff Garzik u32 opts; 1888c6fd2807SJeff Garzik const u32 cmd_fis_len = 5; /* five dwords */ 1889c6fd2807SJeff Garzik unsigned int n_elem; 1890c6fd2807SJeff Garzik 1891c6fd2807SJeff Garzik /* 1892c6fd2807SJeff Garzik * Fill in command table information. First, the header, 1893c6fd2807SJeff Garzik * a SATA Register - Host to Device command FIS. 1894c6fd2807SJeff Garzik */ 1895c6fd2807SJeff Garzik cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; 1896c6fd2807SJeff Garzik 18977d50b60bSTejun Heo ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); 1898c6fd2807SJeff Garzik if (is_atapi) { 1899c6fd2807SJeff Garzik memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); 1900c6fd2807SJeff Garzik memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); 1901c6fd2807SJeff Garzik } 1902c6fd2807SJeff Garzik 1903c6fd2807SJeff Garzik n_elem = 0; 1904c6fd2807SJeff Garzik if (qc->flags & ATA_QCFLAG_DMAMAP) 1905c6fd2807SJeff Garzik n_elem = ahci_fill_sg(qc, cmd_tbl); 1906c6fd2807SJeff Garzik 1907c6fd2807SJeff Garzik /* 1908c6fd2807SJeff Garzik * Fill in command slot information. 1909c6fd2807SJeff Garzik */ 19107d50b60bSTejun Heo opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); 1911c6fd2807SJeff Garzik if (qc->tf.flags & ATA_TFLAG_WRITE) 1912c6fd2807SJeff Garzik opts |= AHCI_CMD_WRITE; 1913c6fd2807SJeff Garzik if (is_atapi) 1914c6fd2807SJeff Garzik opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; 1915c6fd2807SJeff Garzik 1916c6fd2807SJeff Garzik ahci_fill_cmd_slot(pp, qc->tag, opts); 1917c6fd2807SJeff Garzik } 1918c6fd2807SJeff Garzik 1919c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) 1920c6fd2807SJeff Garzik { 1921417a1a6dSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 1922c6fd2807SJeff Garzik struct ahci_port_priv *pp = ap->private_data; 19237d50b60bSTejun Heo struct ata_eh_info *host_ehi = &ap->link.eh_info; 19247d50b60bSTejun Heo struct ata_link *link = NULL; 19257d50b60bSTejun Heo struct ata_queued_cmd *active_qc; 19267d50b60bSTejun Heo struct ata_eh_info *active_ehi; 1927c6fd2807SJeff Garzik u32 serror; 1928c6fd2807SJeff Garzik 19297d50b60bSTejun Heo /* determine active link */ 19307d50b60bSTejun Heo ata_port_for_each_link(link, ap) 19317d50b60bSTejun Heo if (ata_link_active(link)) 19327d50b60bSTejun Heo break; 19337d50b60bSTejun Heo if (!link) 19347d50b60bSTejun Heo link = &ap->link; 19357d50b60bSTejun Heo 19367d50b60bSTejun Heo active_qc = ata_qc_from_tag(ap, link->active_tag); 19377d50b60bSTejun Heo active_ehi = &link->eh_info; 19387d50b60bSTejun Heo 19397d50b60bSTejun Heo /* record irq stat */ 19407d50b60bSTejun Heo ata_ehi_clear_desc(host_ehi); 19417d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); 1942c6fd2807SJeff Garzik 1943c6fd2807SJeff Garzik /* AHCI needs SError cleared; otherwise, it might lock up */ 194482ef04fbSTejun Heo ahci_scr_read(&ap->link, SCR_ERROR, &serror); 194582ef04fbSTejun Heo ahci_scr_write(&ap->link, SCR_ERROR, serror); 19467d50b60bSTejun Heo host_ehi->serror |= serror; 1947c6fd2807SJeff Garzik 194841669553STejun Heo /* some controllers set IRQ_IF_ERR on device errors, ignore it */ 1949417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) 195041669553STejun Heo irq_stat &= ~PORT_IRQ_IF_ERR; 195141669553STejun Heo 195255a61604SConke Hu if (irq_stat & PORT_IRQ_TF_ERR) { 19537d50b60bSTejun Heo /* If qc is active, charge it; otherwise, the active 19547d50b60bSTejun Heo * link. There's no active qc on NCQ errors. It will 19557d50b60bSTejun Heo * be determined by EH by reading log page 10h. 19567d50b60bSTejun Heo */ 19577d50b60bSTejun Heo if (active_qc) 19587d50b60bSTejun Heo active_qc->err_mask |= AC_ERR_DEV; 19597d50b60bSTejun Heo else 19607d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_DEV; 19617d50b60bSTejun Heo 1962417a1a6dSTejun Heo if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) 19637d50b60bSTejun Heo host_ehi->serror &= ~SERR_INTERNAL; 1964c6fd2807SJeff Garzik } 1965c6fd2807SJeff Garzik 1966c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_UNK_FIS) { 1967c6fd2807SJeff Garzik u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); 1968c6fd2807SJeff Garzik 19697d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1970cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 19717d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, 19727d50b60bSTejun Heo "unknown FIS %08x %08x %08x %08x" , 1973c6fd2807SJeff Garzik unk[0], unk[1], unk[2], unk[3]); 1974c6fd2807SJeff Garzik } 1975c6fd2807SJeff Garzik 1976071f44b1STejun Heo if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) { 19777d50b60bSTejun Heo active_ehi->err_mask |= AC_ERR_HSM; 1978cf480626STejun Heo active_ehi->action |= ATA_EH_RESET; 19797d50b60bSTejun Heo ata_ehi_push_desc(active_ehi, "incorrect PMP"); 19807d50b60bSTejun Heo } 1981c6fd2807SJeff Garzik 19827d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { 19837d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_HOST_BUS; 1984cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 19857d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "host bus error"); 19867d50b60bSTejun Heo } 19877d50b60bSTejun Heo 19887d50b60bSTejun Heo if (irq_stat & PORT_IRQ_IF_ERR) { 19897d50b60bSTejun Heo host_ehi->err_mask |= AC_ERR_ATA_BUS; 1990cf480626STejun Heo host_ehi->action |= ATA_EH_RESET; 19917d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "interface fatal error"); 19927d50b60bSTejun Heo } 19937d50b60bSTejun Heo 19947d50b60bSTejun Heo if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 19957d50b60bSTejun Heo ata_ehi_hotplugged(host_ehi); 19967d50b60bSTejun Heo ata_ehi_push_desc(host_ehi, "%s", 19977d50b60bSTejun Heo irq_stat & PORT_IRQ_CONNECT ? 19987d50b60bSTejun Heo "connection status changed" : "PHY RDY changed"); 19997d50b60bSTejun Heo } 20007d50b60bSTejun Heo 20017d50b60bSTejun Heo /* okay, let's hand over to EH */ 2002c6fd2807SJeff Garzik 2003c6fd2807SJeff Garzik if (irq_stat & PORT_IRQ_FREEZE) 2004c6fd2807SJeff Garzik ata_port_freeze(ap); 2005c6fd2807SJeff Garzik else 2006c6fd2807SJeff Garzik ata_port_abort(ap); 2007c6fd2807SJeff Garzik } 2008c6fd2807SJeff Garzik 2009df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap) 2010c6fd2807SJeff Garzik { 2011350756f6STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 20129af5c9c9STejun Heo struct ata_eh_info *ehi = &ap->link.eh_info; 20130291f95fSTejun Heo struct ahci_port_priv *pp = ap->private_data; 20145f226c6bSTejun Heo struct ahci_host_priv *hpriv = ap->host->private_data; 2015b06ce3e5STejun Heo int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 2016c6fd2807SJeff Garzik u32 status, qc_active; 2017459ad688STejun Heo int rc; 2018c6fd2807SJeff Garzik 2019c6fd2807SJeff Garzik status = readl(port_mmio + PORT_IRQ_STAT); 2020c6fd2807SJeff Garzik writel(status, port_mmio + PORT_IRQ_STAT); 2021c6fd2807SJeff Garzik 2022b06ce3e5STejun Heo /* ignore BAD_PMP while resetting */ 2023b06ce3e5STejun Heo if (unlikely(resetting)) 2024b06ce3e5STejun Heo status &= ~PORT_IRQ_BAD_PMP; 2025b06ce3e5STejun Heo 202631556594SKristen Carlson Accardi /* If we are getting PhyRdy, this is 202731556594SKristen Carlson Accardi * just a power state change, we should 202831556594SKristen Carlson Accardi * clear out this, plus the PhyRdy/Comm 202931556594SKristen Carlson Accardi * Wake bits from Serror 203031556594SKristen Carlson Accardi */ 203131556594SKristen Carlson Accardi if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && 203231556594SKristen Carlson Accardi (status & PORT_IRQ_PHYRDY)) { 203331556594SKristen Carlson Accardi status &= ~PORT_IRQ_PHYRDY; 203482ef04fbSTejun Heo ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); 203531556594SKristen Carlson Accardi } 203631556594SKristen Carlson Accardi 2037c6fd2807SJeff Garzik if (unlikely(status & PORT_IRQ_ERROR)) { 2038c6fd2807SJeff Garzik ahci_error_intr(ap, status); 2039c6fd2807SJeff Garzik return; 2040c6fd2807SJeff Garzik } 2041c6fd2807SJeff Garzik 20422f294968SKristen Carlson Accardi if (status & PORT_IRQ_SDB_FIS) { 20435f226c6bSTejun Heo /* If SNotification is available, leave notification 20445f226c6bSTejun Heo * handling to sata_async_notification(). If not, 20455f226c6bSTejun Heo * emulate it by snooping SDB FIS RX area. 20465f226c6bSTejun Heo * 20475f226c6bSTejun Heo * Snooping FIS RX area is probably cheaper than 20485f226c6bSTejun Heo * poking SNotification but some constrollers which 20495f226c6bSTejun Heo * implement SNotification, ICH9 for example, don't 20505f226c6bSTejun Heo * store AN SDB FIS into receive area. 20515f226c6bSTejun Heo */ 20525f226c6bSTejun Heo if (hpriv->cap & HOST_CAP_SNTF) 20535f226c6bSTejun Heo sata_async_notification(ap); 20545f226c6bSTejun Heo else { 20555f226c6bSTejun Heo /* If the 'N' bit in word 0 of the FIS is set, 20565f226c6bSTejun Heo * we just received asynchronous notification. 20575f226c6bSTejun Heo * Tell libata about it. 20582f294968SKristen Carlson Accardi */ 20592f294968SKristen Carlson Accardi const __le32 *f = pp->rx_fis + RX_FIS_SDB; 20602f294968SKristen Carlson Accardi u32 f0 = le32_to_cpu(f[0]); 20612f294968SKristen Carlson Accardi 20627d77b247STejun Heo if (f0 & (1 << 15)) 20637d77b247STejun Heo sata_async_notification(ap); 20642f294968SKristen Carlson Accardi } 20655f226c6bSTejun Heo } 20662f294968SKristen Carlson Accardi 20677d50b60bSTejun Heo /* pp->active_link is valid iff any command is in flight */ 20687d50b60bSTejun Heo if (ap->qc_active && pp->active_link->sactive) 2069c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_SCR_ACT); 2070c6fd2807SJeff Garzik else 2071c6fd2807SJeff Garzik qc_active = readl(port_mmio + PORT_CMD_ISSUE); 2072c6fd2807SJeff Garzik 207379f97dadSTejun Heo rc = ata_qc_complete_multiple(ap, qc_active); 2074b06ce3e5STejun Heo 2075459ad688STejun Heo /* while resetting, invalid completions are expected */ 2076459ad688STejun Heo if (unlikely(rc < 0 && !resetting)) { 2077c6fd2807SJeff Garzik ehi->err_mask |= AC_ERR_HSM; 2078cf480626STejun Heo ehi->action |= ATA_EH_RESET; 2079c6fd2807SJeff Garzik ata_port_freeze(ap); 2080c6fd2807SJeff Garzik } 2081c6fd2807SJeff Garzik } 2082c6fd2807SJeff Garzik 20837d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance) 2084c6fd2807SJeff Garzik { 2085cca3974eSJeff Garzik struct ata_host *host = dev_instance; 2086c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 2087c6fd2807SJeff Garzik unsigned int i, handled = 0; 2088c6fd2807SJeff Garzik void __iomem *mmio; 2089d28f87aaSTejun Heo u32 irq_stat, irq_masked; 2090c6fd2807SJeff Garzik 2091c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2092c6fd2807SJeff Garzik 2093cca3974eSJeff Garzik hpriv = host->private_data; 20940d5ff566STejun Heo mmio = host->iomap[AHCI_PCI_BAR]; 2095c6fd2807SJeff Garzik 2096c6fd2807SJeff Garzik /* sigh. 0xffffffff is a valid return from h/w */ 2097c6fd2807SJeff Garzik irq_stat = readl(mmio + HOST_IRQ_STAT); 2098c6fd2807SJeff Garzik if (!irq_stat) 2099c6fd2807SJeff Garzik return IRQ_NONE; 2100c6fd2807SJeff Garzik 2101d28f87aaSTejun Heo irq_masked = irq_stat & hpriv->port_map; 2102d28f87aaSTejun Heo 2103cca3974eSJeff Garzik spin_lock(&host->lock); 2104c6fd2807SJeff Garzik 2105cca3974eSJeff Garzik for (i = 0; i < host->n_ports; i++) { 2106c6fd2807SJeff Garzik struct ata_port *ap; 2107c6fd2807SJeff Garzik 2108d28f87aaSTejun Heo if (!(irq_masked & (1 << i))) 2109c6fd2807SJeff Garzik continue; 2110c6fd2807SJeff Garzik 2111cca3974eSJeff Garzik ap = host->ports[i]; 2112c6fd2807SJeff Garzik if (ap) { 2113df69c9c5SJeff Garzik ahci_port_intr(ap); 2114c6fd2807SJeff Garzik VPRINTK("port %u\n", i); 2115c6fd2807SJeff Garzik } else { 2116c6fd2807SJeff Garzik VPRINTK("port %u (no irq)\n", i); 2117c6fd2807SJeff Garzik if (ata_ratelimit()) 2118cca3974eSJeff Garzik dev_printk(KERN_WARNING, host->dev, 2119c6fd2807SJeff Garzik "interrupt on disabled port %u\n", i); 2120c6fd2807SJeff Garzik } 2121c6fd2807SJeff Garzik 2122c6fd2807SJeff Garzik handled = 1; 2123c6fd2807SJeff Garzik } 2124c6fd2807SJeff Garzik 2125d28f87aaSTejun Heo /* HOST_IRQ_STAT behaves as level triggered latch meaning that 2126d28f87aaSTejun Heo * it should be cleared after all the port events are cleared; 2127d28f87aaSTejun Heo * otherwise, it will raise a spurious interrupt after each 2128d28f87aaSTejun Heo * valid one. Please read section 10.6.2 of ahci 1.1 for more 2129d28f87aaSTejun Heo * information. 2130d28f87aaSTejun Heo * 2131d28f87aaSTejun Heo * Also, use the unmasked value to clear interrupt as spurious 2132d28f87aaSTejun Heo * pending event on a dummy port might cause screaming IRQ. 2133d28f87aaSTejun Heo */ 2134ea0c62f7STejun Heo writel(irq_stat, mmio + HOST_IRQ_STAT); 2135ea0c62f7STejun Heo 2136cca3974eSJeff Garzik spin_unlock(&host->lock); 2137c6fd2807SJeff Garzik 2138c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 2139c6fd2807SJeff Garzik 2140c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 2141c6fd2807SJeff Garzik } 2142c6fd2807SJeff Garzik 2143c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) 2144c6fd2807SJeff Garzik { 2145c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 21464447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 21477d50b60bSTejun Heo struct ahci_port_priv *pp = ap->private_data; 21487d50b60bSTejun Heo 21497d50b60bSTejun Heo /* Keep track of the currently active link. It will be used 21507d50b60bSTejun Heo * in completion path to determine whether NCQ phase is in 21517d50b60bSTejun Heo * progress. 21527d50b60bSTejun Heo */ 21537d50b60bSTejun Heo pp->active_link = qc->dev->link; 2154c6fd2807SJeff Garzik 2155c6fd2807SJeff Garzik if (qc->tf.protocol == ATA_PROT_NCQ) 2156c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); 2157c6fd2807SJeff Garzik writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); 2158c6fd2807SJeff Garzik 215918f7ba4cSKristen Carlson Accardi ahci_sw_activity(qc->dev->link); 216018f7ba4cSKristen Carlson Accardi 2161c6fd2807SJeff Garzik return 0; 2162c6fd2807SJeff Garzik } 2163c6fd2807SJeff Garzik 21644c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) 21654c9bf4e7STejun Heo { 21664c9bf4e7STejun Heo struct ahci_port_priv *pp = qc->ap->private_data; 21674c9bf4e7STejun Heo u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 21684c9bf4e7STejun Heo 21694c9bf4e7STejun Heo ata_tf_from_fis(d2h_fis, &qc->result_tf); 21704c9bf4e7STejun Heo return true; 21714c9bf4e7STejun Heo } 21724c9bf4e7STejun Heo 2173c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap) 2174c6fd2807SJeff Garzik { 21754447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 2176c6fd2807SJeff Garzik 2177c6fd2807SJeff Garzik /* turn IRQ off */ 2178c6fd2807SJeff Garzik writel(0, port_mmio + PORT_IRQ_MASK); 2179c6fd2807SJeff Garzik } 2180c6fd2807SJeff Garzik 2181c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap) 2182c6fd2807SJeff Garzik { 21830d5ff566STejun Heo void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; 21844447d351STejun Heo void __iomem *port_mmio = ahci_port_base(ap); 2185c6fd2807SJeff Garzik u32 tmp; 2186a7384925SKristen Carlson Accardi struct ahci_port_priv *pp = ap->private_data; 2187c6fd2807SJeff Garzik 2188c6fd2807SJeff Garzik /* clear IRQ */ 2189c6fd2807SJeff Garzik tmp = readl(port_mmio + PORT_IRQ_STAT); 2190c6fd2807SJeff Garzik writel(tmp, port_mmio + PORT_IRQ_STAT); 2191a718728fSTejun Heo writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); 2192c6fd2807SJeff Garzik 21931c954a4dSTejun Heo /* turn IRQ back on */ 21941c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 2195c6fd2807SJeff Garzik } 2196c6fd2807SJeff Garzik 2197c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap) 2198c6fd2807SJeff Garzik { 2199c6fd2807SJeff Garzik if (!(ap->pflags & ATA_PFLAG_FROZEN)) { 2200c6fd2807SJeff Garzik /* restart engine */ 22014447d351STejun Heo ahci_stop_engine(ap); 22024447d351STejun Heo ahci_start_engine(ap); 2203c6fd2807SJeff Garzik } 2204c6fd2807SJeff Garzik 2205a1efdabaSTejun Heo sata_pmp_error_handler(ap); 2206edc93052STejun Heo } 2207edc93052STejun Heo 2208c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 2209c6fd2807SJeff Garzik { 2210c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 2211c6fd2807SJeff Garzik 2212c6fd2807SJeff Garzik /* make DMA engine forget about the failed command */ 2213d2e75dffSTejun Heo if (qc->flags & ATA_QCFLAG_FAILED) 2214d2e75dffSTejun Heo ahci_kick_engine(ap, 1); 2215c6fd2807SJeff Garzik } 2216c6fd2807SJeff Garzik 22177d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap) 22187d50b60bSTejun Heo { 22197d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 22201c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 22217d50b60bSTejun Heo u32 cmd; 22227d50b60bSTejun Heo 22237d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 22247d50b60bSTejun Heo cmd |= PORT_CMD_PMP; 22257d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 22261c954a4dSTejun Heo 22271c954a4dSTejun Heo pp->intr_mask |= PORT_IRQ_BAD_PMP; 22281c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 22297d50b60bSTejun Heo } 22307d50b60bSTejun Heo 22317d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap) 22327d50b60bSTejun Heo { 22337d50b60bSTejun Heo void __iomem *port_mmio = ahci_port_base(ap); 22341c954a4dSTejun Heo struct ahci_port_priv *pp = ap->private_data; 22357d50b60bSTejun Heo u32 cmd; 22367d50b60bSTejun Heo 22377d50b60bSTejun Heo cmd = readl(port_mmio + PORT_CMD); 22387d50b60bSTejun Heo cmd &= ~PORT_CMD_PMP; 22397d50b60bSTejun Heo writel(cmd, port_mmio + PORT_CMD); 22401c954a4dSTejun Heo 22411c954a4dSTejun Heo pp->intr_mask &= ~PORT_IRQ_BAD_PMP; 22421c954a4dSTejun Heo writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); 22437d50b60bSTejun Heo } 22447d50b60bSTejun Heo 2245028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap) 2246028a2596SAlexey Dobriyan { 2247028a2596SAlexey Dobriyan ahci_power_up(ap); 2248028a2596SAlexey Dobriyan ahci_start_port(ap); 2249028a2596SAlexey Dobriyan 2250071f44b1STejun Heo if (sata_pmp_attached(ap)) 22517d50b60bSTejun Heo ahci_pmp_attach(ap); 22527d50b60bSTejun Heo else 22537d50b60bSTejun Heo ahci_pmp_detach(ap); 22547d50b60bSTejun Heo 2255028a2596SAlexey Dobriyan return 0; 2256028a2596SAlexey Dobriyan } 2257028a2596SAlexey Dobriyan 2258438ac6d5STejun Heo #ifdef CONFIG_PM 2259c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) 2260c6fd2807SJeff Garzik { 2261c6fd2807SJeff Garzik const char *emsg = NULL; 2262c6fd2807SJeff Garzik int rc; 2263c6fd2807SJeff Garzik 22644447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 22658e16f941STejun Heo if (rc == 0) 22664447d351STejun Heo ahci_power_down(ap); 22678e16f941STejun Heo else { 2268c6fd2807SJeff Garzik ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); 2269df69c9c5SJeff Garzik ahci_start_port(ap); 2270c6fd2807SJeff Garzik } 2271c6fd2807SJeff Garzik 2272c6fd2807SJeff Garzik return rc; 2273c6fd2807SJeff Garzik } 2274c6fd2807SJeff Garzik 2275c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 2276c6fd2807SJeff Garzik { 2277cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 22780d5ff566STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2279c6fd2807SJeff Garzik u32 ctl; 2280c6fd2807SJeff Garzik 22813a2d5b70SRafael J. Wysocki if (mesg.event & PM_EVENT_SLEEP) { 2282c6fd2807SJeff Garzik /* AHCI spec rev1.1 section 8.3.3: 2283c6fd2807SJeff Garzik * Software must disable interrupts prior to requesting a 2284c6fd2807SJeff Garzik * transition of the HBA to D3 state. 2285c6fd2807SJeff Garzik */ 2286c6fd2807SJeff Garzik ctl = readl(mmio + HOST_CTL); 2287c6fd2807SJeff Garzik ctl &= ~HOST_IRQ_EN; 2288c6fd2807SJeff Garzik writel(ctl, mmio + HOST_CTL); 2289c6fd2807SJeff Garzik readl(mmio + HOST_CTL); /* flush */ 2290c6fd2807SJeff Garzik } 2291c6fd2807SJeff Garzik 2292c6fd2807SJeff Garzik return ata_pci_device_suspend(pdev, mesg); 2293c6fd2807SJeff Garzik } 2294c6fd2807SJeff Garzik 2295c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev) 2296c6fd2807SJeff Garzik { 2297cca3974eSJeff Garzik struct ata_host *host = dev_get_drvdata(&pdev->dev); 2298c6fd2807SJeff Garzik int rc; 2299c6fd2807SJeff Garzik 2300553c4aa6STejun Heo rc = ata_pci_device_do_resume(pdev); 2301553c4aa6STejun Heo if (rc) 2302553c4aa6STejun Heo return rc; 2303c6fd2807SJeff Garzik 2304c6fd2807SJeff Garzik if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 23054447d351STejun Heo rc = ahci_reset_controller(host); 2306c6fd2807SJeff Garzik if (rc) 2307c6fd2807SJeff Garzik return rc; 2308c6fd2807SJeff Garzik 23094447d351STejun Heo ahci_init_controller(host); 2310c6fd2807SJeff Garzik } 2311c6fd2807SJeff Garzik 2312cca3974eSJeff Garzik ata_host_resume(host); 2313c6fd2807SJeff Garzik 2314c6fd2807SJeff Garzik return 0; 2315c6fd2807SJeff Garzik } 2316438ac6d5STejun Heo #endif 2317c6fd2807SJeff Garzik 2318c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap) 2319c6fd2807SJeff Garzik { 2320cca3974eSJeff Garzik struct device *dev = ap->host->dev; 2321c6fd2807SJeff Garzik struct ahci_port_priv *pp; 2322c6fd2807SJeff Garzik void *mem; 2323c6fd2807SJeff Garzik dma_addr_t mem_dma; 2324c6fd2807SJeff Garzik 232524dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 2326c6fd2807SJeff Garzik if (!pp) 2327c6fd2807SJeff Garzik return -ENOMEM; 2328c6fd2807SJeff Garzik 232924dc5f33STejun Heo mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, 233024dc5f33STejun Heo GFP_KERNEL); 233124dc5f33STejun Heo if (!mem) 2332c6fd2807SJeff Garzik return -ENOMEM; 2333c6fd2807SJeff Garzik memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); 2334c6fd2807SJeff Garzik 2335c6fd2807SJeff Garzik /* 2336c6fd2807SJeff Garzik * First item in chunk of DMA memory: 32-slot command table, 2337c6fd2807SJeff Garzik * 32 bytes each in size 2338c6fd2807SJeff Garzik */ 2339c6fd2807SJeff Garzik pp->cmd_slot = mem; 2340c6fd2807SJeff Garzik pp->cmd_slot_dma = mem_dma; 2341c6fd2807SJeff Garzik 2342c6fd2807SJeff Garzik mem += AHCI_CMD_SLOT_SZ; 2343c6fd2807SJeff Garzik mem_dma += AHCI_CMD_SLOT_SZ; 2344c6fd2807SJeff Garzik 2345c6fd2807SJeff Garzik /* 2346c6fd2807SJeff Garzik * Second item: Received-FIS area 2347c6fd2807SJeff Garzik */ 2348c6fd2807SJeff Garzik pp->rx_fis = mem; 2349c6fd2807SJeff Garzik pp->rx_fis_dma = mem_dma; 2350c6fd2807SJeff Garzik 2351c6fd2807SJeff Garzik mem += AHCI_RX_FIS_SZ; 2352c6fd2807SJeff Garzik mem_dma += AHCI_RX_FIS_SZ; 2353c6fd2807SJeff Garzik 2354c6fd2807SJeff Garzik /* 2355c6fd2807SJeff Garzik * Third item: data area for storing a single command 2356c6fd2807SJeff Garzik * and its scatter-gather table 2357c6fd2807SJeff Garzik */ 2358c6fd2807SJeff Garzik pp->cmd_tbl = mem; 2359c6fd2807SJeff Garzik pp->cmd_tbl_dma = mem_dma; 2360c6fd2807SJeff Garzik 2361a7384925SKristen Carlson Accardi /* 2362a7384925SKristen Carlson Accardi * Save off initial list of interrupts to be enabled. 2363a7384925SKristen Carlson Accardi * This could be changed later 2364a7384925SKristen Carlson Accardi */ 2365a7384925SKristen Carlson Accardi pp->intr_mask = DEF_PORT_IRQ; 2366a7384925SKristen Carlson Accardi 2367c6fd2807SJeff Garzik ap->private_data = pp; 2368c6fd2807SJeff Garzik 2369df69c9c5SJeff Garzik /* engage engines, captain */ 2370df69c9c5SJeff Garzik return ahci_port_resume(ap); 2371c6fd2807SJeff Garzik } 2372c6fd2807SJeff Garzik 2373c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap) 2374c6fd2807SJeff Garzik { 2375c6fd2807SJeff Garzik const char *emsg = NULL; 2376c6fd2807SJeff Garzik int rc; 2377c6fd2807SJeff Garzik 2378c6fd2807SJeff Garzik /* de-initialize port */ 23794447d351STejun Heo rc = ahci_deinit_port(ap, &emsg); 2380c6fd2807SJeff Garzik if (rc) 2381c6fd2807SJeff Garzik ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); 2382c6fd2807SJeff Garzik } 2383c6fd2807SJeff Garzik 23844447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) 2385c6fd2807SJeff Garzik { 2386c6fd2807SJeff Garzik int rc; 2387c6fd2807SJeff Garzik 2388c6fd2807SJeff Garzik if (using_dac && 2389c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 2390c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 2391c6fd2807SJeff Garzik if (rc) { 2392c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2393c6fd2807SJeff Garzik if (rc) { 2394c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2395c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 2396c6fd2807SJeff Garzik return rc; 2397c6fd2807SJeff Garzik } 2398c6fd2807SJeff Garzik } 2399c6fd2807SJeff Garzik } else { 2400c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 2401c6fd2807SJeff Garzik if (rc) { 2402c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2403c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 2404c6fd2807SJeff Garzik return rc; 2405c6fd2807SJeff Garzik } 2406c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 2407c6fd2807SJeff Garzik if (rc) { 2408c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 2409c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 2410c6fd2807SJeff Garzik return rc; 2411c6fd2807SJeff Garzik } 2412c6fd2807SJeff Garzik } 2413c6fd2807SJeff Garzik return 0; 2414c6fd2807SJeff Garzik } 2415c6fd2807SJeff Garzik 24164447d351STejun Heo static void ahci_print_info(struct ata_host *host) 2417c6fd2807SJeff Garzik { 24184447d351STejun Heo struct ahci_host_priv *hpriv = host->private_data; 24194447d351STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 24204447d351STejun Heo void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; 2421c6fd2807SJeff Garzik u32 vers, cap, impl, speed; 2422c6fd2807SJeff Garzik const char *speed_s; 2423c6fd2807SJeff Garzik u16 cc; 2424c6fd2807SJeff Garzik const char *scc_s; 2425c6fd2807SJeff Garzik 2426c6fd2807SJeff Garzik vers = readl(mmio + HOST_VERSION); 2427c6fd2807SJeff Garzik cap = hpriv->cap; 2428c6fd2807SJeff Garzik impl = hpriv->port_map; 2429c6fd2807SJeff Garzik 2430c6fd2807SJeff Garzik speed = (cap >> 20) & 0xf; 2431c6fd2807SJeff Garzik if (speed == 1) 2432c6fd2807SJeff Garzik speed_s = "1.5"; 2433c6fd2807SJeff Garzik else if (speed == 2) 2434c6fd2807SJeff Garzik speed_s = "3"; 2435c6fd2807SJeff Garzik else 2436c6fd2807SJeff Garzik speed_s = "?"; 2437c6fd2807SJeff Garzik 2438c6fd2807SJeff Garzik pci_read_config_word(pdev, 0x0a, &cc); 2439c9f89475SConke Hu if (cc == PCI_CLASS_STORAGE_IDE) 2440c6fd2807SJeff Garzik scc_s = "IDE"; 2441c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_SATA) 2442c6fd2807SJeff Garzik scc_s = "SATA"; 2443c9f89475SConke Hu else if (cc == PCI_CLASS_STORAGE_RAID) 2444c6fd2807SJeff Garzik scc_s = "RAID"; 2445c6fd2807SJeff Garzik else 2446c6fd2807SJeff Garzik scc_s = "unknown"; 2447c6fd2807SJeff Garzik 2448c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2449c6fd2807SJeff Garzik "AHCI %02x%02x.%02x%02x " 2450c6fd2807SJeff Garzik "%u slots %u ports %s Gbps 0x%x impl %s mode\n" 2451c6fd2807SJeff Garzik , 2452c6fd2807SJeff Garzik 2453c6fd2807SJeff Garzik (vers >> 24) & 0xff, 2454c6fd2807SJeff Garzik (vers >> 16) & 0xff, 2455c6fd2807SJeff Garzik (vers >> 8) & 0xff, 2456c6fd2807SJeff Garzik vers & 0xff, 2457c6fd2807SJeff Garzik 2458c6fd2807SJeff Garzik ((cap >> 8) & 0x1f) + 1, 2459c6fd2807SJeff Garzik (cap & 0x1f) + 1, 2460c6fd2807SJeff Garzik speed_s, 2461c6fd2807SJeff Garzik impl, 2462c6fd2807SJeff Garzik scc_s); 2463c6fd2807SJeff Garzik 2464c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, 2465c6fd2807SJeff Garzik "flags: " 2466203ef6c4STejun Heo "%s%s%s%s%s%s%s" 246718f7ba4cSKristen Carlson Accardi "%s%s%s%s%s%s%s" 246818f7ba4cSKristen Carlson Accardi "%s\n" 2469c6fd2807SJeff Garzik , 2470c6fd2807SJeff Garzik 2471c6fd2807SJeff Garzik cap & (1 << 31) ? "64bit " : "", 2472c6fd2807SJeff Garzik cap & (1 << 30) ? "ncq " : "", 2473203ef6c4STejun Heo cap & (1 << 29) ? "sntf " : "", 2474c6fd2807SJeff Garzik cap & (1 << 28) ? "ilck " : "", 2475c6fd2807SJeff Garzik cap & (1 << 27) ? "stag " : "", 2476c6fd2807SJeff Garzik cap & (1 << 26) ? "pm " : "", 2477c6fd2807SJeff Garzik cap & (1 << 25) ? "led " : "", 2478c6fd2807SJeff Garzik 2479c6fd2807SJeff Garzik cap & (1 << 24) ? "clo " : "", 2480c6fd2807SJeff Garzik cap & (1 << 19) ? "nz " : "", 2481c6fd2807SJeff Garzik cap & (1 << 18) ? "only " : "", 2482c6fd2807SJeff Garzik cap & (1 << 17) ? "pmp " : "", 2483c6fd2807SJeff Garzik cap & (1 << 15) ? "pio " : "", 2484c6fd2807SJeff Garzik cap & (1 << 14) ? "slum " : "", 248518f7ba4cSKristen Carlson Accardi cap & (1 << 13) ? "part " : "", 248618f7ba4cSKristen Carlson Accardi cap & (1 << 6) ? "ems ": "" 2487c6fd2807SJeff Garzik ); 2488c6fd2807SJeff Garzik } 2489c6fd2807SJeff Garzik 2490edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is 2491edc93052STejun Heo * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't 2492edc93052STejun Heo * support PMP and the 4726 either directly exports the device 2493edc93052STejun Heo * attached to the first downstream port or acts as a hardware storage 2494edc93052STejun Heo * controller and emulate a single ATA device (can be RAID 0/1 or some 2495edc93052STejun Heo * other configuration). 2496edc93052STejun Heo * 2497edc93052STejun Heo * When there's no device attached to the first downstream port of the 2498edc93052STejun Heo * 4726, "Config Disk" appears, which is a pseudo ATA device to 2499edc93052STejun Heo * configure the 4726. However, ATA emulation of the device is very 2500edc93052STejun Heo * lame. It doesn't send signature D2H Reg FIS after the initial 2501edc93052STejun Heo * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues. 2502edc93052STejun Heo * 2503edc93052STejun Heo * The following function works around the problem by always using 2504edc93052STejun Heo * hardreset on the port and not depending on receiving signature FIS 2505edc93052STejun Heo * afterward. If signature FIS isn't received soon, ATA class is 2506edc93052STejun Heo * assumed without follow-up softreset. 2507edc93052STejun Heo */ 2508edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host) 2509edc93052STejun Heo { 2510edc93052STejun Heo static struct dmi_system_id sysids[] = { 2511edc93052STejun Heo { 2512edc93052STejun Heo .ident = "P5W DH Deluxe", 2513edc93052STejun Heo .matches = { 2514edc93052STejun Heo DMI_MATCH(DMI_SYS_VENDOR, 2515edc93052STejun Heo "ASUSTEK COMPUTER INC"), 2516edc93052STejun Heo DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"), 2517edc93052STejun Heo }, 2518edc93052STejun Heo }, 2519edc93052STejun Heo { } 2520edc93052STejun Heo }; 2521edc93052STejun Heo struct pci_dev *pdev = to_pci_dev(host->dev); 2522edc93052STejun Heo 2523edc93052STejun Heo if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) && 2524edc93052STejun Heo dmi_check_system(sysids)) { 2525edc93052STejun Heo struct ata_port *ap = host->ports[1]; 2526edc93052STejun Heo 2527edc93052STejun Heo dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH " 2528edc93052STejun Heo "Deluxe on-board SIMG4726 workaround\n"); 2529edc93052STejun Heo 2530edc93052STejun Heo ap->ops = &ahci_p5wdh_ops; 2531edc93052STejun Heo ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA; 2532edc93052STejun Heo } 2533edc93052STejun Heo } 2534edc93052STejun Heo 2535c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2536c6fd2807SJeff Garzik { 2537c6fd2807SJeff Garzik static int printed_version; 2538e297d99eSTejun Heo unsigned int board_id = ent->driver_data; 2539e297d99eSTejun Heo struct ata_port_info pi = ahci_port_info[board_id]; 25404447d351STejun Heo const struct ata_port_info *ppi[] = { &pi, NULL }; 254124dc5f33STejun Heo struct device *dev = &pdev->dev; 2542c6fd2807SJeff Garzik struct ahci_host_priv *hpriv; 25434447d351STejun Heo struct ata_host *host; 2544837f5f8fSTejun Heo int n_ports, i, rc; 2545c6fd2807SJeff Garzik 2546c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 2547c6fd2807SJeff Garzik 2548c6fd2807SJeff Garzik WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); 2549c6fd2807SJeff Garzik 2550c6fd2807SJeff Garzik if (!printed_version++) 2551c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 2552c6fd2807SJeff Garzik 25535b66c829SAlan Cox /* The AHCI driver can only drive the SATA ports, the PATA driver 25545b66c829SAlan Cox can drive them all so if both drivers are selected make sure 25555b66c829SAlan Cox AHCI stays out of the way */ 25565b66c829SAlan Cox if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable) 25575b66c829SAlan Cox return -ENODEV; 25585b66c829SAlan Cox 25594447d351STejun Heo /* acquire resources */ 256024dc5f33STejun Heo rc = pcim_enable_device(pdev); 2561c6fd2807SJeff Garzik if (rc) 2562c6fd2807SJeff Garzik return rc; 2563c6fd2807SJeff Garzik 2564dea55137STejun Heo /* AHCI controllers often implement SFF compatible interface. 2565dea55137STejun Heo * Grab all PCI BARs just in case. 2566dea55137STejun Heo */ 2567dea55137STejun Heo rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); 25680d5ff566STejun Heo if (rc == -EBUSY) 256924dc5f33STejun Heo pcim_pin_device(pdev); 25700d5ff566STejun Heo if (rc) 257124dc5f33STejun Heo return rc; 2572c6fd2807SJeff Garzik 2573c4f7792cSTejun Heo if (pdev->vendor == PCI_VENDOR_ID_INTEL && 2574c4f7792cSTejun Heo (pdev->device == 0x2652 || pdev->device == 0x2653)) { 2575c4f7792cSTejun Heo u8 map; 2576c4f7792cSTejun Heo 2577c4f7792cSTejun Heo /* ICH6s share the same PCI ID for both piix and ahci 2578c4f7792cSTejun Heo * modes. Enabling ahci mode while MAP indicates 2579c4f7792cSTejun Heo * combined mode is a bad idea. Yield to ata_piix. 2580c4f7792cSTejun Heo */ 2581c4f7792cSTejun Heo pci_read_config_byte(pdev, ICH_MAP, &map); 2582c4f7792cSTejun Heo if (map & 0x3) { 2583c4f7792cSTejun Heo dev_printk(KERN_INFO, &pdev->dev, "controller is in " 2584c4f7792cSTejun Heo "combined mode, can't enable AHCI mode\n"); 2585c4f7792cSTejun Heo return -ENODEV; 2586c4f7792cSTejun Heo } 2587c4f7792cSTejun Heo } 2588c4f7792cSTejun Heo 258924dc5f33STejun Heo hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 259024dc5f33STejun Heo if (!hpriv) 259124dc5f33STejun Heo return -ENOMEM; 2592417a1a6dSTejun Heo hpriv->flags |= (unsigned long)pi.private_data; 2593417a1a6dSTejun Heo 2594e297d99eSTejun Heo /* MCP65 revision A1 and A2 can't do MSI */ 2595e297d99eSTejun Heo if (board_id == board_ahci_mcp65 && 2596e297d99eSTejun Heo (pdev->revision == 0xa1 || pdev->revision == 0xa2)) 2597e297d99eSTejun Heo hpriv->flags |= AHCI_HFLAG_NO_MSI; 2598e297d99eSTejun Heo 2599417a1a6dSTejun Heo if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) 2600417a1a6dSTejun Heo pci_intx(pdev, 1); 2601c6fd2807SJeff Garzik 26024447d351STejun Heo /* save initial config */ 2603417a1a6dSTejun Heo ahci_save_initial_config(pdev, hpriv); 2604c6fd2807SJeff Garzik 26054447d351STejun Heo /* prepare host */ 2606274c1fdeSTejun Heo if (hpriv->cap & HOST_CAP_NCQ) 26074447d351STejun Heo pi.flags |= ATA_FLAG_NCQ; 26084447d351STejun Heo 26097d50b60bSTejun Heo if (hpriv->cap & HOST_CAP_PMP) 26107d50b60bSTejun Heo pi.flags |= ATA_FLAG_PMP; 26117d50b60bSTejun Heo 261218f7ba4cSKristen Carlson Accardi if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) { 261318f7ba4cSKristen Carlson Accardi u8 messages; 261418f7ba4cSKristen Carlson Accardi void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; 261518f7ba4cSKristen Carlson Accardi u32 em_loc = readl(mmio + HOST_EM_LOC); 261618f7ba4cSKristen Carlson Accardi u32 em_ctl = readl(mmio + HOST_EM_CTL); 261718f7ba4cSKristen Carlson Accardi 261818f7ba4cSKristen Carlson Accardi messages = (em_ctl & 0x000f0000) >> 16; 261918f7ba4cSKristen Carlson Accardi 262018f7ba4cSKristen Carlson Accardi /* we only support LED message type right now */ 262118f7ba4cSKristen Carlson Accardi if ((messages & 0x01) && (ahci_em_messages == 1)) { 262218f7ba4cSKristen Carlson Accardi /* store em_loc */ 262318f7ba4cSKristen Carlson Accardi hpriv->em_loc = ((em_loc >> 16) * 4); 262418f7ba4cSKristen Carlson Accardi pi.flags |= ATA_FLAG_EM; 262518f7ba4cSKristen Carlson Accardi if (!(em_ctl & EM_CTL_ALHD)) 262618f7ba4cSKristen Carlson Accardi pi.flags |= ATA_FLAG_SW_ACTIVITY; 262718f7ba4cSKristen Carlson Accardi } 262818f7ba4cSKristen Carlson Accardi } 262918f7ba4cSKristen Carlson Accardi 2630837f5f8fSTejun Heo /* CAP.NP sometimes indicate the index of the last enabled 2631837f5f8fSTejun Heo * port, at other times, that of the last possible port, so 2632837f5f8fSTejun Heo * determining the maximum port number requires looking at 2633837f5f8fSTejun Heo * both CAP.NP and port_map. 2634837f5f8fSTejun Heo */ 2635837f5f8fSTejun Heo n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 2636837f5f8fSTejun Heo 2637837f5f8fSTejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 26384447d351STejun Heo if (!host) 26394447d351STejun Heo return -ENOMEM; 26404447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 26414447d351STejun Heo host->private_data = hpriv; 26424447d351STejun Heo 264318f7ba4cSKristen Carlson Accardi if (pi.flags & ATA_FLAG_EM) 264418f7ba4cSKristen Carlson Accardi ahci_reset_em(host); 264518f7ba4cSKristen Carlson Accardi 26464447d351STejun Heo for (i = 0; i < host->n_ports; i++) { 26474447d351STejun Heo struct ata_port *ap = host->ports[i]; 26484447d351STejun Heo 2649cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); 2650cbcdd875STejun Heo ata_port_pbar_desc(ap, AHCI_PCI_BAR, 2651cbcdd875STejun Heo 0x100 + ap->port_no * 0x80, "port"); 2652cbcdd875STejun Heo 265331556594SKristen Carlson Accardi /* set initial link pm policy */ 265431556594SKristen Carlson Accardi ap->pm_policy = NOT_AVAILABLE; 265531556594SKristen Carlson Accardi 265618f7ba4cSKristen Carlson Accardi /* set enclosure management message type */ 265718f7ba4cSKristen Carlson Accardi if (ap->flags & ATA_FLAG_EM) 265818f7ba4cSKristen Carlson Accardi ap->em_message_type = ahci_em_messages; 265918f7ba4cSKristen Carlson Accardi 266018f7ba4cSKristen Carlson Accardi 2661dab632e8SJeff Garzik /* disabled/not-implemented port */ 2662350756f6STejun Heo if (!(hpriv->port_map & (1 << i))) 2663dab632e8SJeff Garzik ap->ops = &ata_dummy_port_ops; 26644447d351STejun Heo } 2665c6fd2807SJeff Garzik 2666edc93052STejun Heo /* apply workaround for ASUS P5W DH Deluxe mainboard */ 2667edc93052STejun Heo ahci_p5wdh_workaround(host); 2668edc93052STejun Heo 2669c6fd2807SJeff Garzik /* initialize adapter */ 26704447d351STejun Heo rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2671c6fd2807SJeff Garzik if (rc) 267224dc5f33STejun Heo return rc; 2673c6fd2807SJeff Garzik 26744447d351STejun Heo rc = ahci_reset_controller(host); 26754447d351STejun Heo if (rc) 26764447d351STejun Heo return rc; 2677c6fd2807SJeff Garzik 26784447d351STejun Heo ahci_init_controller(host); 26794447d351STejun Heo ahci_print_info(host); 2680c6fd2807SJeff Garzik 26814447d351STejun Heo pci_set_master(pdev); 26824447d351STejun Heo return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, 26834447d351STejun Heo &ahci_sht); 2684c6fd2807SJeff Garzik } 2685c6fd2807SJeff Garzik 2686c6fd2807SJeff Garzik static int __init ahci_init(void) 2687c6fd2807SJeff Garzik { 2688c6fd2807SJeff Garzik return pci_register_driver(&ahci_pci_driver); 2689c6fd2807SJeff Garzik } 2690c6fd2807SJeff Garzik 2691c6fd2807SJeff Garzik static void __exit ahci_exit(void) 2692c6fd2807SJeff Garzik { 2693c6fd2807SJeff Garzik pci_unregister_driver(&ahci_pci_driver); 2694c6fd2807SJeff Garzik } 2695c6fd2807SJeff Garzik 2696c6fd2807SJeff Garzik 2697c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik"); 2698c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver"); 2699c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 2700c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); 2701c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 2702c6fd2807SJeff Garzik 2703c6fd2807SJeff Garzik module_init(ahci_init); 2704c6fd2807SJeff Garzik module_exit(ahci_exit); 2705