diff options
-rw-r--r-- | drivers/ata/Makefile | 2 | ||||
-rw-r--r-- | drivers/ata/ahci.c | 2280 | ||||
-rw-r--r-- | drivers/ata/ahci.h | 332 | ||||
-rw-r--r-- | drivers/ata/libahci.c | 2091 |
4 files changed, 2425 insertions, 2280 deletions
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index fc936d4471d..20c5251e7e4 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_ATA) += libata.o -obj-$(CONFIG_SATA_AHCI) += ahci.o +obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o obj-$(CONFIG_SATA_SVW) += sata_svw.o obj-$(CONFIG_ATA_PIIX) += ata_piix.o obj-$(CONFIG_SATA_PROMISE) += sata_promise.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index d5dc1238a88..feaefb84ffa 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -46,67 +46,13 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <linux/libata.h> +#include "ahci.h" #define DRV_NAME "ahci" #define DRV_VERSION "3.0" -/* Enclosure Management Control */ -#define EM_CTRL_MSG_TYPE 0x000f0000 - -/* Enclosure Management LED Message Type */ -#define EM_MSG_LED_HBA_PORT 0x0000000f -#define EM_MSG_LED_PMP_SLOT 0x0000ff00 -#define EM_MSG_LED_VALUE 0xffff0000 -#define EM_MSG_LED_VALUE_ACTIVITY 0x00070000 -#define EM_MSG_LED_VALUE_OFF 0xfff80000 -#define EM_MSG_LED_VALUE_ON 0x00010000 - -static int ahci_skip_host_reset; -static int ahci_ignore_sss; - -module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444); -MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)"); - -module_param_named(ignore_sss, ahci_ignore_sss, int, 0444); -MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)"); - -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy); -static void ahci_disable_alpm(struct ata_port *ap); -static ssize_t ahci_led_show(struct ata_port *ap, char *buf); -static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, - size_t size); -static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, - ssize_t size); - enum { AHCI_PCI_BAR = 5, - AHCI_MAX_PORTS = 32, - AHCI_MAX_SG = 168, /* hardware max is 64K */ - AHCI_DMA_BOUNDARY = 0xffffffff, - AHCI_MAX_CMDS = 32, - AHCI_CMD_SZ = 32, - AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, - AHCI_RX_FIS_SZ = 256, - AHCI_CMD_TBL_CDB = 0x40, - AHCI_CMD_TBL_HDR_SZ = 0x80, - AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), - AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, - AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + - AHCI_RX_FIS_SZ, - AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ + - AHCI_CMD_TBL_AR_SZ + - (AHCI_RX_FIS_SZ * 16), - AHCI_IRQ_ON_SG = (1 << 31), - AHCI_CMD_ATAPI = (1 << 5), - AHCI_CMD_WRITE = (1 << 6), - AHCI_CMD_PREFETCH = (1 << 7), - AHCI_CMD_RESET = (1 << 8), - AHCI_CMD_CLR_BUSY = (1 << 10), - - RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ - RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ - RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, board_ahci_vt8251 = 1, @@ -118,332 +64,19 @@ enum { board_ahci_nopmp = 7, board_ahci_yesncq = 8, board_ahci_nosntf = 9, - - /* global controller registers */ - HOST_CAP = 0x00, /* host capabilities */ - HOST_CTL = 0x04, /* global host control */ - HOST_IRQ_STAT = 0x08, /* interrupt status */ - HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ - HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ - HOST_EM_LOC = 0x1c, /* Enclosure Management location */ - HOST_EM_CTL = 0x20, /* Enclosure Management Control */ - HOST_CAP2 = 0x24, /* host capabilities, extended */ - - /* HOST_CTL bits */ - HOST_RESET = (1 << 0), /* reset controller; self-clear */ - HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ - HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ - - /* HOST_CAP bits */ - HOST_CAP_SXS = (1 << 5), /* Supports External SATA */ - HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ - HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */ - HOST_CAP_PART = (1 << 13), /* Partial state capable */ - HOST_CAP_SSC = (1 << 14), /* Slumber state capable */ - HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */ - HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */ - HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ - HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */ - HOST_CAP_CLO = (1 << 24), /* Command List Override support */ - HOST_CAP_LED = (1 << 25), /* Supports activity LED */ - HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ - HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ - HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */ - HOST_CAP_SNTF = (1 << 29), /* SNotification register */ - HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ - HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ - - /* HOST_CAP2 bits */ - HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ - HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ - HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ - - /* registers for each SATA port */ - PORT_LST_ADDR = 0x00, /* command list DMA addr */ - PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ - PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ - PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ - PORT_IRQ_STAT = 0x10, /* interrupt status */ - PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ - PORT_CMD = 0x18, /* port command */ - PORT_TFDATA = 0x20, /* taskfile data */ - PORT_SIG = 0x24, /* device TF signature */ - PORT_CMD_ISSUE = 0x38, /* command issue */ - PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ - PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ - PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ - PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ - PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ - PORT_FBS = 0x40, /* FIS-based Switching */ - - /* PORT_IRQ_{STAT,MASK} bits */ - PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ - PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ - PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ - PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ - PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ - PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ - PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ - PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ - - PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ - PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ - PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ - PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ - PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ - PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ - PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ - PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ - PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ - - PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | - PORT_IRQ_IF_ERR | - PORT_IRQ_CONNECT | - PORT_IRQ_PHYRDY | - PORT_IRQ_UNK_FIS | - PORT_IRQ_BAD_PMP, - PORT_IRQ_ERROR = PORT_IRQ_FREEZE | - PORT_IRQ_TF_ERR | - PORT_IRQ_HBUS_DATA_ERR, - DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | - PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | - PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, - - /* PORT_CMD bits */ - PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ - PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ - PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ - PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */ - PORT_CMD_PMP = (1 << 17), /* PMP attached */ - PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ - PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ - PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ - PORT_CMD_CLO = (1 << 3), /* Command list override */ - PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ - PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ - PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ - - PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ - PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ - PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ - PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ - - PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ - PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ - PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ - PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */ - PORT_FBS_SDE = (1 << 2), /* FBS single device error */ - PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ - PORT_FBS_EN = (1 << 0), /* Enable FBS */ - - /* hpriv->flags bits */ - AHCI_HFLAG_NO_NCQ = (1 << 0), - AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ - AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ - AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ - AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ - AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ - AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ - AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ - AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ - AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ - AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ - AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as - link offline */ - AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ - - /* ap->flags bits */ - - AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | - ATA_FLAG_IPM, - - ICH_MAP = 0x90, /* ICH MAP register */ - - /* em constants */ - EM_MAX_SLOTS = 8, - EM_MAX_RETRY = 5, - - /* em_ctl bits */ - EM_CTL_RST = (1 << 9), /* Reset */ - EM_CTL_TM = (1 << 8), /* Transmit Message */ - EM_CTL_ALHD = (1 << 26), /* Activity LED */ -}; - -struct ahci_cmd_hdr { - __le32 opts; - __le32 status; - __le32 tbl_addr; - __le32 tbl_addr_hi; - __le32 reserved[4]; -}; - -struct ahci_sg { - __le32 addr; - __le32 addr_hi; - __le32 reserved; - __le32 flags_size; -}; - -struct ahci_em_priv { - enum sw_activity blink_policy; - struct timer_list timer; - unsigned long saved_activity; - unsigned long activity; - unsigned long led_state; }; -struct ahci_host_priv { - void __iomem * mmio; /* bus-independant mem map */ - unsigned int flags; /* AHCI_HFLAG_* */ - u32 cap; /* cap to use */ - u32 cap2; /* cap2 to use */ - u32 port_map; /* port map to use */ - u32 saved_cap; /* saved initial cap */ - u32 saved_cap2; /* saved initial cap2 */ - u32 saved_port_map; /* saved initial port_map */ - u32 em_loc; /* enclosure management location */ -}; - -struct ahci_port_priv { - struct ata_link *active_link; - struct ahci_cmd_hdr *cmd_slot; - dma_addr_t cmd_slot_dma; - void *cmd_tbl; - dma_addr_t cmd_tbl_dma; - void *rx_fis; - dma_addr_t rx_fis_dma; - /* for NCQ spurious interrupt analysis */ - unsigned int ncq_saw_d2h:1; - unsigned int ncq_saw_dmas:1; - unsigned int ncq_saw_sdb:1; - u32 intr_mask; /* interrupts to enable */ - bool fbs_supported; /* set iff FBS is supported */ - bool fbs_enabled; /* set iff FBS is enabled */ - int fbs_last_dev; /* save FBS.DEV of last FIS */ - /* enclosure management info per PM slot */ - struct ahci_em_priv em_priv[EM_MAX_SLOTS]; -}; - -static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); -static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); -static int ahci_port_start(struct ata_port *ap); -static void ahci_port_stop(struct ata_port *ap); -static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc); -static void ahci_qc_prep(struct ata_queued_cmd *qc); -static void ahci_freeze(struct ata_port *ap); -static void ahci_thaw(struct ata_port *ap); -static void ahci_enable_fbs(struct ata_port *ap); -static void ahci_disable_fbs(struct ata_port *ap); -static void ahci_pmp_attach(struct ata_port *ap); -static void ahci_pmp_detach(struct ata_port *ap); -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static int ahci_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static void ahci_postreset(struct ata_link *link, unsigned int *class); -static void ahci_error_handler(struct ata_port *ap); -static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); -static int ahci_port_resume(struct ata_port *ap); -static void ahci_dev_config(struct ata_device *dev); -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, - u32 opts); #ifdef CONFIG_PM -static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int ahci_pci_device_resume(struct pci_dev *pdev); #endif -static ssize_t ahci_activity_show(struct ata_device *dev, char *buf); -static ssize_t ahci_activity_store(struct ata_device *dev, - enum sw_activity val); -static void ahci_init_sw_activity(struct ata_link *link); - -static ssize_t ahci_show_host_caps(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ahci_show_host_cap2(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ahci_show_host_version(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ahci_show_port_cmd(struct device *dev, - struct device_attribute *attr, char *buf); - -static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); -static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); -static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); -static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); - -static struct device_attribute *ahci_shost_attrs[] = { - &dev_attr_link_power_management_policy, - &dev_attr_em_message_type, - &dev_attr_em_message, - &dev_attr_ahci_host_caps, - &dev_attr_ahci_host_cap2, - &dev_attr_ahci_host_version, - &dev_attr_ahci_port_cmd, - NULL -}; - -static struct device_attribute *ahci_sdev_attrs[] = { - &dev_attr_sw_activity, - &dev_attr_unload_heads, - NULL -}; - -static struct scsi_host_template ahci_sht = { - ATA_NCQ_SHT(DRV_NAME), - .can_queue = AHCI_MAX_CMDS - 1, - .sg_tablesize = AHCI_MAX_SG, - .dma_boundary = AHCI_DMA_BOUNDARY, - .shost_attrs = ahci_shost_attrs, - .sdev_attrs = ahci_sdev_attrs, -}; - -static struct ata_port_operations ahci_ops = { - .inherits = &sata_pmp_port_ops, - - .qc_defer = ahci_pmp_qc_defer, - .qc_prep = ahci_qc_prep, - .qc_issue = ahci_qc_issue, - .qc_fill_rtf = ahci_qc_fill_rtf, - - .freeze = ahci_freeze, - .thaw = ahci_thaw, - .softreset = ahci_softreset, - .hardreset = ahci_hardreset, - .postreset = ahci_postreset, - .pmp_softreset = ahci_softreset, - .error_handler = ahci_error_handler, - .post_internal_cmd = ahci_post_internal_cmd, - .dev_config = ahci_dev_config, - - .scr_read = ahci_scr_read, - .scr_write = ahci_scr_write, - .pmp_attach = ahci_pmp_attach, - .pmp_detach = ahci_pmp_detach, - - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, - .em_show = ahci_led_show, - .em_store = ahci_led_store, - .sw_activity_show = ahci_activity_show, - .sw_activity_store = ahci_activity_store, -#ifdef CONFIG_PM - .port_suspend = ahci_port_suspend, - .port_resume = ahci_port_resume, -#endif - .port_start = ahci_port_start, - .port_stop = ahci_port_stop, -}; static struct ata_port_operations ahci_vt8251_ops = { .inherits = &ahci_ops, @@ -738,12 +371,6 @@ static struct pci_driver ahci_pci_driver = { #endif }; -static int ahci_em_messages = 1; -module_param(ahci_em_messages, int, 0444); -/* add other LED protocol types when they become supported */ -MODULE_PARM_DESC(ahci_em_messages, - "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED"); - #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE) static int marvell_enable; #else @@ -753,214 +380,6 @@ module_param(marvell_enable, int, 0644); MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); -static inline int ahci_nr_ports(u32 cap) -{ - return (cap & 0x1f) + 1; -} - -static inline void __iomem *__ahci_port_base(struct ata_host *host, - unsigned int port_no) -{ - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = hpriv->mmio; - - return mmio + 0x100 + (port_no * 0x80); -} - -static inline void __iomem *ahci_port_base(struct ata_port *ap) -{ - return __ahci_port_base(ap->host, ap->port_no); -} - -static void ahci_enable_ahci(void __iomem *mmio) -{ - int i; - u32 tmp; - - /* turn on AHCI_EN */ - tmp = readl(mmio + HOST_CTL); - if (tmp & HOST_AHCI_EN) - return; - - /* Some controllers need AHCI_EN to be written multiple times. - * Try a few times before giving up. - */ - for (i = 0; i < 5; i++) { - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ - if (tmp & HOST_AHCI_EN) - return; - msleep(10); - } - - WARN_ON(1); -} - -static ssize_t ahci_show_host_caps(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ata_port *ap = ata_shost_to_port(shost); - struct ahci_host_priv *hpriv = ap->host->private_data; - - return sprintf(buf, "%x\n", hpriv->cap); -} - -static ssize_t ahci_show_host_cap2(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ata_port *ap = ata_shost_to_port(shost); - struct ahci_host_priv *hpriv = ap->host->private_data; - - return sprintf(buf, "%x\n", hpriv->cap2); -} - -static ssize_t ahci_show_host_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ata_port *ap = ata_shost_to_port(shost); - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = hpriv->mmio; - - return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION)); -} - -static ssize_t ahci_show_port_cmd(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ata_port *ap = ata_shost_to_port(shost); - void __iomem *port_mmio = ahci_port_base(ap); - - return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD)); -} - -/** - * ahci_save_initial_config - Save and fixup initial config values - * @dev: target AHCI device - * @hpriv: host private area to store config values - * @force_port_map: force port map to a specified value - * @mask_port_map: mask out particular bits from port map - * - * Some registers containing configuration info might be setup by - * BIOS and might be cleared on reset. This function saves the - * initial values of those registers into @hpriv such that they - * can be restored after controller reset. - * - * If inconsistent, config values are fixed up by this function. - * - * LOCKING: - * None. - */ -static void ahci_save_initial_config(struct device *dev, - struct ahci_host_priv *hpriv, - unsigned int force_port_map, - unsigned int mask_port_map) -{ - void __iomem *mmio = hpriv->mmio; - u32 cap, cap2, vers, port_map; - int i; - - /* make sure AHCI mode is enabled before accessing CAP */ - ahci_enable_ahci(mmio); - - /* Values prefixed with saved_ are written back to host after - * reset. Values without are used for driver operation. - */ - hpriv->saved_cap = cap = readl(mmio + HOST_CAP); - hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); - - /* CAP2 register is only defined for AHCI 1.2 and later */ - vers = readl(mmio + HOST_VERSION); - if ((vers >> 16) > 1 || - ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200)) - hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2); - else - hpriv->saved_cap2 = cap2 = 0; - - /* some chips have errata preventing 64bit use */ - if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { - dev_printk(KERN_INFO, dev, - "controller can't do 64bit DMA, forcing 32bit\n"); - cap &= ~HOST_CAP_64; - } - - if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { - dev_printk(KERN_INFO, dev, - "controller can't do NCQ, turning off CAP_NCQ\n"); - cap &= ~HOST_CAP_NCQ; - } - - if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { - dev_printk(KERN_INFO, dev, - "controller can do NCQ, turning on CAP_NCQ\n"); - cap |= HOST_CAP_NCQ; - } - - if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { - dev_printk(KERN_INFO, dev, - "controller can't do PMP, turning off CAP_PMP\n"); - cap &= ~HOST_CAP_PMP; - } - - if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) { - dev_printk(KERN_INFO, dev, - "controller can't do SNTF, turning off CAP_SNTF\n"); - cap &= ~HOST_CAP_SNTF; - } - - if (force_port_map && port_map != force_port_map) { - dev_printk(KERN_INFO, dev, "forcing port_map 0x%x -> 0x%x\n", - port_map, force_port_map); - port_map = force_port_map; - } - - if (mask_port_map) { - dev_printk(KERN_ERR, dev, "masking port_map 0x%x -> 0x%x\n", - port_map, - port_map & mask_port_map); - port_map &= mask_port_map; - } - - /* cross check port_map and cap.n_ports */ - if (port_map) { - int map_ports = 0; - - for (i = 0; i < AHCI_MAX_PORTS; i++) - if (port_map & (1 << i)) - map_ports++; - - /* If PI has more ports than n_ports, whine, clear - * port_map and let it be generated from n_ports. - */ - if (map_ports > ahci_nr_ports(cap)) { - dev_printk(KERN_WARNING, dev, - "implemented port map (0x%x) contains more " - "ports than nr_ports (%u), using nr_ports\n", - port_map, ahci_nr_ports(cap)); - port_map = 0; - } - } - - /* fabricate port_map from cap.nr_ports */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_printk(KERN_WARNING, dev, - "forcing PORTS_IMPL to 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; - } - - /* record values to use during operation */ - hpriv->cap = cap; - hpriv->cap2 = cap2; - hpriv->port_map = port_map; -} - static void ahci_pci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { @@ -990,421 +409,6 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev, mask_port_map); } -/** - * ahci_restore_initial_config - Restore initial config - * @host: target ATA host - * - * Restore initial config stored by ahci_save_initial_config(). - * - * LOCKING: - * None. - */ -static void ahci_restore_initial_config(struct ata_host *host) -{ - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = hpriv->mmio; - - writel(hpriv->saved_cap, mmio + HOST_CAP); - if (hpriv->saved_cap2) - writel(hpriv->saved_cap2, mmio + HOST_CAP2); - writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); - (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ -} - -static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) -{ - static const int offset[] = { - [SCR_STATUS] = PORT_SCR_STAT, - [SCR_CONTROL] = PORT_SCR_CTL, - [SCR_ERROR] = PORT_SCR_ERR, - [SCR_ACTIVE] = PORT_SCR_ACT, - [SCR_NOTIFICATION] = PORT_SCR_NTF, - }; - struct ahci_host_priv *hpriv = ap->host->private_data; - - if (sc_reg < ARRAY_SIZE(offset) && - (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) - return offset[sc_reg]; - return 0; -} - -static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - int offset = ahci_scr_offset(link->ap, sc_reg); - - if (offset) { - *val = readl(port_mmio + offset); - return 0; - } - return -EINVAL; -} - -static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - int offset = ahci_scr_offset(link->ap, sc_reg); - - if (offset) { - writel(val, port_mmio + offset); - return 0; - } - return -EINVAL; -} - -static void ahci_start_engine(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - /* start DMA */ - tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_START; - writel(tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ -} - -static int ahci_stop_engine(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - tmp = readl(port_mmio + PORT_CMD); - - /* check if the HBA is idle */ - if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) - return 0; - - /* setting HBA to idle */ - tmp &= ~PORT_CMD_START; - writel(tmp, port_mmio + PORT_CMD); - - /* wait for engine to stop. This could be as long as 500 msec */ - tmp = ata_wait_register(port_mmio + PORT_CMD, - PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); - if (tmp & PORT_CMD_LIST_ON) - return -EIO; - - return 0; -} - -static void ahci_start_fis_rx(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; - u32 tmp; - - /* set FIS registers */ - if (hpriv->cap & HOST_CAP_64) - writel((pp->cmd_slot_dma >> 16) >> 16, - port_mmio + PORT_LST_ADDR_HI); - writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); - - if (hpriv->cap & HOST_CAP_64) - writel((pp->rx_fis_dma >> 16) >> 16, - port_mmio + PORT_FIS_ADDR_HI); - writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); - - /* enable FIS reception */ - tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_FIS_RX; - writel(tmp, port_mmio + PORT_CMD); - - /* flush */ - readl(port_mmio + PORT_CMD); -} - -static int ahci_stop_fis_rx(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - /* disable FIS reception */ - tmp = readl(port_mmio + PORT_CMD); - tmp &= ~PORT_CMD_FIS_RX; - writel(tmp, port_mmio + PORT_CMD); - - /* wait for completion, spec says 500ms, give it 1000 */ - tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, - PORT_CMD_FIS_ON, 10, 1000); - if (tmp & PORT_CMD_FIS_ON) - return -EBUSY; - - return 0; -} - -static void ahci_power_up(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - - cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; - - /* spin up device */ - if (hpriv->cap & HOST_CAP_SSS) { - cmd |= PORT_CMD_SPIN_UP; - writel(cmd, port_mmio + PORT_CMD); - } - - /* wake up link */ - writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); -} - -static void ahci_disable_alpm(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - struct ahci_port_priv *pp = ap->private_data; - - /* IPM bits should be disabled by libata-core */ - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); - - /* disable ALPM and ASP */ - cmd &= ~PORT_CMD_ASP; - cmd &= ~PORT_CMD_ALPE; - - /* force the interface back to active */ - cmd |= PORT_CMD_ICC_ACTIVE; - - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); - - /* wait 10ms to be sure we've come out of any low power state */ - msleep(10); - - /* clear out any PhyRdy stuff from interrupt status */ - writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); - - /* go ahead and clean out PhyRdy Change from Serror too */ - ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); - - /* - * Clear flag to indicate that we should ignore all PhyRdy - * state changes - */ - hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; - - /* - * Enable interrupts on Phy Ready. - */ - pp->intr_mask |= PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); - - /* - * don't change the link pm policy - we can be called - * just to turn of link pm temporarily - */ -} - -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - struct ahci_port_priv *pp = ap->private_data; - u32 asp; - - /* Make sure the host is capable of link power management */ - if (!(hpriv->cap & HOST_CAP_ALPM)) - return -EINVAL; - - switch (policy) { - case MAX_PERFORMANCE: - case NOT_AVAILABLE: - /* - * if we came here with NOT_AVAILABLE, - * it just means this is the first time we - * have tried to enable - default to max performance, - * and let the user go to lower power modes on request. - */ - ahci_disable_alpm(ap); - return 0; - case MIN_POWER: - /* configure HBA to enter SLUMBER */ - asp = PORT_CMD_ASP; - break; - case MEDIUM_POWER: - /* configure HBA to enter PARTIAL */ - asp = 0; - break; - default: - return -EINVAL; - } - - /* - * Disable interrupts on Phy Ready. This keeps us from - * getting woken up due to spurious phy ready interrupts - * TBD - Hot plug should be done via polling now, is - * that even supported? - */ - pp->intr_mask &= ~PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); - - /* - * Set a flag to indicate that we should ignore all PhyRdy - * state changes since these can happen now whenever we - * change link state - */ - hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; - - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); - - /* - * Set ASP based on Policy - */ - cmd |= asp; - - /* - * Setting this bit will instruct the HBA to aggressively - * enter a lower power link state when it's appropriate and - * based on the value set above for ASP - */ - cmd |= PORT_CMD_ALPE; - - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); - - /* IPM bits should be set by libata-core */ - return 0; -} - -#ifdef CONFIG_PM -static void ahci_power_down(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd, scontrol; - - if (!(hpriv->cap & HOST_CAP_SSS)) - return; - - /* put device into listen mode, first set PxSCTL.DET to 0 */ - scontrol = readl(port_mmio + PORT_SCR_CTL); - scontrol &= ~0xf; - writel(scontrol, port_mmio + PORT_SCR_CTL); - - /* then set PxCMD.SUD to 0 */ - cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; - cmd &= ~PORT_CMD_SPIN_UP; - writel(cmd, port_mmio + PORT_CMD); -} -#endif - -static void ahci_start_port(struct ata_port *ap) -{ - struct ahci_port_priv *pp = ap->private_data; - struct ata_link *link; - struct ahci_em_priv *emp; - ssize_t rc; - int i; - - /* enable FIS reception */ - ahci_start_fis_rx(ap); - - /* enable DMA */ - ahci_start_engine(ap); - - /* turn on LEDs */ - if (ap->flags & ATA_FLAG_EM) { - ata_for_each_link(link, ap, EDGE) { - emp = &pp->em_priv[link->pmp]; - - /* EM Transmit bit maybe busy during init */ - for (i = 0; i < EM_MAX_RETRY; i++) { - rc = ahci_transmit_led_message(ap, - emp->led_state, - 4); - if (rc == -EBUSY) - msleep(1); - else - break; - } - } - } - - if (ap->flags & ATA_FLAG_SW_ACTIVITY) - ata_for_each_link(link, ap, EDGE) - ahci_init_sw_activity(link); - -} - -static int ahci_deinit_port(struct ata_port *ap, const char **emsg) -{ - int rc; - - /* disable DMA */ - rc = ahci_stop_engine(ap); - if (rc) { - *emsg = "failed to stop engine"; - return rc; - } - - /* disable FIS reception */ - rc = ahci_stop_fis_rx(ap); - if (rc) { - *emsg = "failed stop FIS RX"; - return rc; - } - - return 0; -} - -static int ahci_reset_controller(struct ata_host *host) -{ - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = hpriv->mmio; - u32 tmp; - - /* we must be in AHCI mode, before using anything - * AHCI-specific, such as HOST_RESET. - */ - ahci_enable_ahci(mmio); - - /* global controller reset */ - if (!ahci_skip_host_reset) { - tmp = readl(mmio + HOST_CTL); - if ((tmp & HOST_RESET) == 0) { - writel(tmp | HOST_RESET, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - } - - /* - * to perform host reset, OS should set HOST_RESET - * and poll until this bit is read to be "0". - * reset must complete within 1 second, or - * the hardware should be considered fried. - */ - tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET, - HOST_RESET, 10, 1000); - - if (tmp & HOST_RESET) { - dev_printk(KERN_ERR, host->dev, - "controller reset failed (0x%x)\n", tmp); - return -EIO; - } - - /* turn on AHCI mode */ - ahci_enable_ahci(mmio); - - /* Some registers might be cleared on reset. Restore - * initial values. - */ - ahci_restore_initial_config(host); - } else - dev_printk(KERN_INFO, host->dev, - "skipping global host reset\n"); - - return 0; -} - static int ahci_pci_reset_controller(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); @@ -1426,286 +430,6 @@ static int ahci_pci_reset_controller(struct ata_host *host) return 0; } -static void ahci_sw_activity(struct ata_link *link) -{ - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - - if (!(link->flags & ATA_LFLAG_SW_ACTIVITY)) - return; - - emp->activity++; - if (!timer_pending(&emp->timer)) - mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10)); -} - -static void ahci_sw_activity_blink(unsigned long arg) -{ - struct ata_link *link = (struct ata_link *)arg; - struct ata_port *ap = link->ap; - struct ahci_por |