diff options
Diffstat (limited to 'drivers/ata')
85 files changed, 2052 insertions, 747 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4e737728aee2..20e03a7eb8b4 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -11,13 +11,13 @@ config HAVE_PATA_PLATFORM to update the PATA_PLATFORM entry. menuconfig ATA - tristate "Serial ATA and Parallel ATA drivers" + tristate "Serial ATA and Parallel ATA drivers (libata)" depends on HAS_IOMEM depends on BLOCK depends on !(M32R || M68K || S390) || BROKEN select SCSI ---help--- - If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or + If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or any other ATA device under Linux, say Y and make sure that you know the name of your ATA host adapter (the card inside your computer that "speaks" the ATA protocol, also called ATA controller), @@ -60,7 +60,7 @@ config ATA_ACPI config SATA_ZPODD bool "SATA Zero Power Optical Disc Drive (ZPODD) support" - depends on ATA_ACPI + depends on ATA_ACPI && PM_RUNTIME default n help This option adds support for SATA Zero Power Optical Disc @@ -97,15 +97,48 @@ config SATA_AHCI_PLATFORM If unsure, say N. +config AHCI_DA850 + tristate "DaVinci DA850 AHCI SATA support" + depends on ARCH_DAVINCI_DA850 + help + This option enables support for the DaVinci DA850 SoC's + onboard AHCI SATA. + + If unsure, say N. + +config AHCI_ST + tristate "ST AHCI SATA support" + depends on ARCH_STI + help + This option enables support for ST AHCI SATA controller. + + If unsure, say N. + config AHCI_IMX tristate "Freescale i.MX AHCI SATA support" - depends on SATA_AHCI_PLATFORM && MFD_SYSCON + depends on MFD_SYSCON help This option enables support for the Freescale i.MX SoC's onboard AHCI SATA. If unsure, say N. +config AHCI_SUNXI + tristate "Allwinner sunxi AHCI SATA support" + depends on ARCH_SUNXI + help + This option enables support for the Allwinner sunxi SoC's + onboard AHCI SATA. + + If unsure, say N. + +config AHCI_XGENE + tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" + depends on ARM64 || COMPILE_TEST + select PHY_XGENE + help + This option enables support for APM X-Gene SoC SATA host controller. + config SATA_FSL tristate "Freescale 3.0Gbps SATA support" depends on FSL_SOC @@ -239,6 +272,7 @@ config SATA_DWC_VDEBUG config SATA_HIGHBANK tristate "Calxeda Highbank SATA support" + depends on ARCH_HIGHBANK || COMPILE_TEST help This option enables support for the Calxeda Highbank SoC's onboard SATA. @@ -247,6 +281,9 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \ + ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST + select GENERIC_PHY help This option enables support for the Marvell Serial ATA family. Currently supports 88SX[56]0[48][01] PCI(-X) chips, @@ -272,6 +309,7 @@ config SATA_PROMISE config SATA_RCAR tristate "Renesas R-Car SATA support" + depends on ARCH_SHMOBILE || COMPILE_TEST help This option enables support for Renesas R-Car Serial ATA. @@ -351,6 +389,7 @@ config PATA_AMD config PATA_ARASAN_CF tristate "ARASAN CompactFlash PATA Controller Support" + depends on ARCH_SPEAR13XX || COMPILE_TEST depends on DMADEVICES select DMA_ENGINE help @@ -402,7 +441,7 @@ config PATA_CMD64X config PATA_CS5520 tristate "CS5510/5520 PATA support" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) help This option enables support for the Cyrix 5510/5520 companion chip used with the MediaGX/Geode processor family. @@ -411,7 +450,7 @@ config PATA_CS5520 config PATA_CS5530 tristate "CS5530 PATA support" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) help This option enables support for the Cyrix/NatSemi/AMD CS5530 companion chip used with the MediaGX/Geode processor family. @@ -420,7 +459,7 @@ config PATA_CS5530 config PATA_CS5535 tristate "CS5535 PATA support (Experimental)" - depends on PCI && X86 && !X86_64 + depends on PCI && X86_32 help This option enables support for the NatSemi/AMD CS5535 companion chip used with the Geode processor family. @@ -429,7 +468,7 @@ config PATA_CS5535 config PATA_CS5536 tristate "CS5536 PATA support" - depends on PCI + depends on PCI && (X86_32 || MIPS || COMPILE_TEST) help This option enables support for the AMD CS5536 companion chip used with the Geode LX processor family. @@ -665,7 +704,7 @@ config PATA_RDC config PATA_SC1200 tristate "SC1200 PATA support" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) help This option enables support for the NatSemi/AMD SC1200 SoC companion chip used with the Geode processor family. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 46518c622460..44c8016e565c 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -4,13 +4,17 @@ obj-$(CONFIG_ATA) += libata.o # non-SFF interface obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o -obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o +obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o -obj-$(CONFIG_AHCI_IMX) += ahci_imx.o +obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index fd665d919df2..b51605ac5974 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -36,7 +36,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dc2756fb6f33..5a0bf8ed649b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -61,6 +60,7 @@ enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_noncq, board_ahci_nosntf, board_ahci_yes_fbs, @@ -121,6 +121,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_noncq] = { + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_nosntf] = { AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), .flags = AHCI_FLAG_COMMON, @@ -452,6 +459,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ + /* + * Samsung SSDs found on some macbooks. NCQ times out. + * https://bugzilla.kernel.org/show_bug.cgi?id=60731 + */ + { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq }, + /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, @@ -564,6 +577,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; bool online; int rc; @@ -574,7 +588,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); - ahci_start_engine(ap); + hpriv->start_engine(ap); DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); @@ -589,6 +603,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -604,7 +619,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline, &online, NULL); - ahci_start_engine(ap); + hpriv->start_engine(ap); /* The pseudo configuration device on SIMG4726 attached to * ASUS P5W-DH Deluxe doesn't send signature FIS after @@ -1151,13 +1166,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { - int rc, nvec; + int nvec; if (hpriv->flags & AHCI_HFLAG_NO_MSI) goto intx; - rc = pci_msi_vec_count(pdev); - if (rc < 0) + nvec = pci_msi_vec_count(pdev); + if (nvec < 0) goto intx; /* @@ -1165,19 +1180,19 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, * Message mode could be enforced. In this case assume that advantage * of multipe MSIs is negated and use single MSI mode instead. */ - if (rc < n_ports) + if (nvec < n_ports) goto single_msi; - nvec = rc; - rc = pci_enable_msi_block(pdev, nvec); - if (rc) + nvec = pci_enable_msi_range(pdev, nvec, nvec); + if (nvec == -ENOSPC) + goto single_msi; + else if (nvec < 0) goto intx; return nvec; single_msi: - rc = pci_enable_msi(pdev); - if (rc) + if (pci_enable_msi(pdev)) goto intx; return 1; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 2289efdf8203..51af275b3388 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -37,6 +37,8 @@ #include <linux/clk.h> #include <linux/libata.h> +#include <linux/phy/phy.h> +#include <linux/regulator/consumer.h> /* Enclosure Management Control */ #define EM_CTRL_MSG_TYPE 0x000f0000 @@ -51,6 +53,7 @@ enum { AHCI_MAX_PORTS = 32, + AHCI_MAX_CLKS = 3, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_MAX_CMDS = 32, @@ -321,8 +324,17 @@ struct ahci_host_priv { u32 em_loc; /* enclosure management location */ u32 em_buf_sz; /* EM buffer size in byte */ u32 em_msg_type; /* EM message type */ - struct clk *clk; /* Only for platforms supporting clk */ + bool got_runtime_pm; /* Did we do pm_runtime_get? */ + struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ + struct regulator *target_pwr; /* Optional */ + struct phy *phy; /* If platform uses phy */ void *plat_data; /* Other platform data */ + /* + * Optional ahci_start_engine override, if not set this gets set to the + * default ahci_start_engine during ahci_save_initial_config, this can + * be overridden anytime before the host is activated. + */ + void (*start_engine)(struct ata_port *ap); }; extern int ahci_ignore_sss; diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c new file mode 100644 index 000000000000..2c83613ce2db --- /dev/null +++ b/drivers/ata/ahci_da850.c @@ -0,0 +1,114 @@ +/* + * DaVinci DA850 AHCI SATA platform driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/libata.h> +#include <linux/ahci_platform.h> +#include "ahci.h" + +/* SATA PHY Control Register offset from AHCI base */ +#define SATA_P0PHYCR_REG 0x178 + +#define SATA_PHY_MPY(x) ((x) << 0) +#define SATA_PHY_LOS(x) ((x) << 6) +#define SATA_PHY_RXCDR(x) ((x) << 10) +#define SATA_PHY_RXEQ(x) ((x) << 13) +#define SATA_PHY_TXSWING(x) ((x) << 19) +#define SATA_PHY_ENPLL(x) ((x) << 31) + +/* + * The multiplier needed for 1.5GHz PLL output. + * + * NOTE: This is currently hardcoded to be suitable for 100MHz crystal + * frequency (which is used by DA850 EVM board) and may need to be changed + * if you would like to use this driver on some other board. + */ +#define DA850_SATA_CLK_MULTIPLIER 7 + +static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg, + void __iomem *ahci_base) +{ + unsigned int val; + + /* Enable SATA clock receiver */ + val = readl(pwrdn_reg); + val &= ~BIT(0); + writel(val, pwrdn_reg); + + val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) | + SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | + SATA_PHY_ENPLL(1); + + writel(val, ahci_base + SATA_P0PHYCR_REG); +} + +static const struct ata_port_info ahci_da850_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static int ahci_da850_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct resource *res; + void __iomem *pwrdn_reg; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + goto disable_resources; + + pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res)); + if (!pwrdn_reg) + goto disable_resources; + + da850_sata_init(dev, pwrdn_reg, hpriv->mmio); + + rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 0, 0); + if (rc) + goto disable_resources; + + return 0; +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend, + ahci_platform_resume); + +static struct platform_driver ahci_da850_driver = { + .probe = ahci_da850_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "ahci_da850", + .owner = THIS_MODULE, + .pm = &ahci_da850_pm_ops, + }, +}; +module_platform_driver(ahci_da850_driver); + +MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver"); +MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index dd4d6f74d7bd..497c7abe1c7d 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -42,13 +42,7 @@ enum ahci_imx_type { struct imx_ahci_priv { struct platform_device *ahci_pdev; enum ahci_imx_type type; - - /* i.MX53 clock */ - struct clk *sata_gate_clk; - /* Common clock */ - struct clk *sata_ref_clk; struct clk *ahb_clk; - struct regmap *gpr; bool no_device; bool first_time; @@ -58,28 +52,52 @@ static int ahci_imx_hotplug; module_param_named(hotplug, ahci_imx_hotplug, int, 0644); MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); -static int imx_sata_clock_enable(struct device *dev) +static void ahci_imx_host_stop(struct ata_host *host); + +static int imx_sata_enable(struct ahci_host_priv *hpriv) { - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); + struct imx_ahci_priv *imxpriv = hpriv->plat_data; int ret; - if (imxpriv->type == AHCI_IMX53) { - ret = clk_prepare_enable(imxpriv->sata_gate_clk); - if (ret < 0) { - dev_err(dev, "prepare-enable sata_gate clock err:%d\n", - ret); + if (imxpriv->no_device) + return 0; + + if (hpriv->target_pwr) { + ret = regulator_enable(hpriv->target_pwr); + if (ret) return ret; - } } - ret = clk_prepare_enable(imxpriv->sata_ref_clk); - if (ret < 0) { - dev_err(dev, "prepare-enable sata_ref clock err:%d\n", - ret); - goto clk_err; - } + ret = ahci_platform_enable_clks(hpriv); + if (ret < 0) + goto disable_regulator; if (imxpriv->type == AHCI_IMX6Q) { + /* + * set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write + * is 0x07ffffff, and the other one write for setting + * the mpll_clk_en. + */ + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | + IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | + IMX6Q_GPR13_SATA_SPD_MODE_MASK | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_MASK | + IMX6Q_GPR13_SATA_TX_BOOST_MASK | + IMX6Q_GPR13_SATA_TX_LVL_MASK | + IMX6Q_GPR13_SATA_MPLL_CLK_EN | + IMX6Q_GPR13_SATA_TX_EDGE_RATE, + IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | + IMX6Q_GPR13_SATA_SPD_MODE_3P0G | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | + IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | + IMX6Q_GPR13_SATA_TX_LVL_1_025_V); regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, IMX6Q_GPR13_SATA_MPLL_CLK_EN, IMX6Q_GPR13_SATA_MPLL_CLK_EN); @@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev) return 0; -clk_err: - if (imxpriv->type == AHCI_IMX53) - clk_disable_unprepare(imxpriv->sata_gate_clk); +disable_regulator: + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); + return ret; } -static void imx_sata_clock_disable(struct device *dev) +static void imx_sata_disable(struct ahci_host_priv *hpriv) { - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); + struct imx_ahci_priv *imxpriv = hpriv->plat_data; + + if (imxpriv->no_device) + return; if (imxpriv->type == AHCI_IMX6Q) { regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, @@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev) !IMX6Q_GPR13_SATA_MPLL_CLK_EN); } - clk_disable_unprepare(imxpriv->sata_ref_clk); + ahci_platform_disable_clks(hpriv); - if (imxpriv->type == AHCI_IMX53) - clk_disable_unprepare(imxpriv->sata_gate_clk); + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); } static void ahci_imx_error_handler(struct ata_port *ap) @@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap) struct ata_host *host = dev_get_drvdata(ap->dev); struct ahci_host_priv *hpriv = host->private_data; void __iomem *mmio = hpriv->mmio; - struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); + struct imx_ahci_priv *imxpriv = hpriv->plat_data; ahci_error_handler(ap); @@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap) */ reg_val = readl(mmio + PORT_PHY_CTL); writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); - imx_sata_clock_disable(ap->dev); + imx_sata_disable(hpriv); imxpriv->no_device = true; } @@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_port *ap = link->ap; - struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); + struct ata_host *host = dev_get_drvdata(ap->dev); + struct ahci_host_priv *hpriv = host->private_data; + struct imx_ahci_priv *imxpriv = hpriv->plat_data; int ret = -EIO; if (imxpriv->type == AHCI_IMX53) @@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, } static struct ata_port_operations ahci_imx_ops = { - .inherits = &ahci_platform_ops, + .inherits = &ahci_ops, + .host_stop = ahci_imx_host_stop, .error_handler = ahci_imx_error_handler, .softreset = ahci_imx_softreset, }; @@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = { .port_ops = &ahci_imx_ops, }; -static int imx_sata_init(struct device *dev, void __iomem *mmio) -{ - int ret = 0; - unsigned int reg_val; - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - - ret = imx_sata_clock_enable(dev); - if (ret < 0) - return ret; - - /* - * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, - * and IP vendor specific register HOST_TIMER1MS. - * Configure CAP_SSS (support stagered spin up). - * Implement the port0. - * Get the ahb clock rate, and configure the TIMER1MS register. - */ - reg_val = readl(mmio + HOST_CAP); - if (!(reg_val & HOST_CAP_SSS)) { - reg_val |= HOST_CAP_SSS; - writel(reg_val, mmio + HOST_CAP); - } - reg_val = readl(mmio + HOST_PORTS_IMPL); - if (!(reg_val & 0x1)) { - reg_val |= 0x1; - writel(reg_val, mmio + HOST_PORTS_IMPL); - } - - reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; - writel(reg_val, mmio + HOST_TIMER1MS); - - return 0; -} - -static void imx_sata_exit(struct device *dev) -{ - imx_sata_clock_disable(dev); -} - -static int imx_ahci_suspend(struct device *dev) -{ - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - - /* - * If no_device is set, The CLKs had been gated off in the - * initialization so don't do it again here. - */ - if (!imxpriv->no_device) - imx_sata_clock_disable(dev); - - return 0; -} - -static int imx_ahci_resume(struct device *dev) -{ - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - int ret = 0; - - if (!imxpriv->no_device) - ret = imx_sata_clock_enable(dev); - - return ret; -} - -static struct ahci_platform_data imx_sata_pdata = { - .init = imx_sata_init, - .exit = imx_sata_exit, - .ata_port_info = &ahci_imx_port_info, - .suspend = imx_ahci_suspend, - .resume = imx_ahci_resume, - -}; - static const struct of_device_id imx_ahci_of_match[] = { { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, @@ -251,151 +203,124 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match); static int imx_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *mem, *irq, res[2]; const struct of_device_id *of_id; - enum ahci_imx_type type; - const struct ahci_platform_data *pdata = NULL; + struct ahci_host_priv *hpriv; struct imx_ahci_priv *imxpriv; - struct device *ahci_dev; - struct platform_device *ahci_pdev; + unsigned int reg_val; int ret; of_id = of_match_device(imx_ahci_of_match, dev); if (!of_id) return -EINVAL; - type = (enum ahci_imx_type)of_id->data; - pdata = &imx_sata_pdata; - imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); - if (!imxpriv) { - dev_err(dev, "can't alloc ahci_host_priv\n"); + if (!imxpriv) return -ENOMEM; - } - - ahci_pdev = platform_device_alloc("ahci", -1); - if (!ahci_pdev) - return -ENODEV; - - ahci_dev = &ahci_pdev->dev; - ahci_dev->parent = dev; imxpriv->no_device = false; imxpriv->first_time = true; - imxpriv->type = type; - + imxpriv->type = (enum ahci_imx_type)of_id->data; imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); if (IS_ERR(imxpriv->ahb_clk)) { dev_err(dev, "can't get ahb clock.\n"); - ret = PTR_ERR(imxpriv->ahb_clk); - goto err_out; + return PTR_ERR(imxpriv->ahb_clk); } - if (type == AHCI_IMX53) { - imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate"); - if (IS_ERR(imxpriv->sata_gate_clk)) { - dev_err(dev, "can't get sata_gate clock.\n"); - ret = PTR_ERR(imxpriv->sata_gate_clk); - goto err_out; + if (imxpriv->type == AHCI_IMX6Q) { + imxpriv->gpr = syscon_regmap_lookup_by_compatible( + "fsl,imx6q-iomuxc-gpr"); + if (IS_ERR(imxpriv->gpr)) { + dev_err(dev, + "failed to find fsl,imx6q-iomux-gpr regmap\n"); + return PTR_ERR(imxpriv->gpr); } } - imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); - if (IS_ERR(imxpriv->sata_ref_clk)) { - dev_err(dev, "can't get sata_ref clock.\n"); - ret = PTR_ERR(imxpriv->sata_ref_clk); - goto err_out; - } + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + hpriv->plat_data = imxpriv; - imxpriv->ahci_pdev = ahci_pdev; - platform_set_drvdata(pdev, imxpriv); + ret = imx_sata_enable(hpriv); + if (ret) + return ret; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mem || !irq) { - dev_err(dev, "no mmio/irq resource\n"); - ret = -ENOMEM; - goto err_out; + /* + * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, + * and IP vendor specific register HOST_TIMER1MS. + * Configure CAP_SSS (support stagered spin up). + * Implement the port0. + * Get the ahb clock rate, and configure the TIMER1MS register. + */ + reg_val = readl(hpriv->mmio + HOST_CAP); + if (!(reg_val & HOST_CAP_SSS)) { + reg_val |= HOST_CAP_SSS; + writel(reg_val, hpriv->mmio + HOST_CAP); + } + reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL); + if (!(reg_val & 0x1)) { + reg_val |= 0x1; + writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL); } - res[0] = *mem; - res[1] = *irq; + reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; + writel(reg_val, hpriv->mmio + HOST_TIMER1MS); - ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32); - ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask; - ahci_dev->of_node = dev->of_node; + ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0); + if (ret) + imx_sata_disable(hpriv); - if (type == AHCI_IMX6Q) { - imxpriv->gpr = syscon_regmap_lookup_by_compatible( - "fsl,imx6q-iomuxc-gpr"); - if (IS_ERR(imxpriv->gpr)) { - dev_err(dev, - "failed to find fsl,imx6q-iomux-gpr regmap\n"); - ret = PTR_ERR(imxpriv->gpr); - goto err_out; - } + return ret; +} - /* - * Set PHY Paremeters, two steps to configure the GPR13, - * one write for rest of parameters, mask of first write - * is 0x07fffffe, and the other one write for setting - * the mpll_clk_en happens in imx_sata_clock_enable(). - */ - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | - IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | - IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | - IMX6Q_GPR13_SATA_SPD_MODE_MASK | - IMX6Q_GPR13_SATA_MPLL_SS_EN | - IMX6Q_GPR13_SATA_TX_ATTEN_MASK | - IMX6Q_GPR13_SATA_TX_BOOST_MASK | - IMX6Q_GPR13_SATA_TX_LVL_MASK | - IMX6Q_GPR13_SATA_MPLL_CLK_EN | - IMX6Q_GPR13_SATA_TX_EDGE_RATE, - IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | - IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | - IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | - IMX6Q_GPR13_SATA_SPD_MODE_3P0G | - IMX6Q_GPR13_SATA_MPLL_SS_EN | - IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | - IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | - IMX6Q_GPR13_SATA_TX_LVL_1_025_V); - } +static void ahci_imx_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; - ret = platform_device_add_resources(ahci_pdev, res, 2); - if (ret) - goto err_out; + imx_sata_disable(hpriv); +} - ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata)); - if (ret) - goto err_out; +#ifdef CONFIG_PM_SLEEP +static int imx_ahci_suspend(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int ret; - ret = platform_device_add(ahci_pdev); - if (ret) { -err_out: - platform_device_put(ahci_pdev); + ret = ahci_platform_suspend_host(dev); + if (ret) return ret; - } + + imx_sata_disable(hpriv); return 0; } -static int imx_ahci_remove(struct platform_device *pdev) +static int imx_ahci_resume(struct device *dev) { - struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev); - struct platform_device *ahci_pdev = imxpriv->ahci_pdev; + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int ret; - platform_device_unregister(ahci_pdev); - return 0; + ret = imx_sata_enable(hpriv); + if (ret) + return ret; + + return ahci_platform_resume_host(dev); } +#endif + +static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); static struct platform_driver imx_ahci_driver = { .probe = imx_ahci_probe, - .remove = imx_ahci_remove, + .remove = ata_platform_remove_one, .driver = { .name = "ahci-imx", .owner = THIS_MODULE, .of_match_table = imx_ahci_of_match, + .pm = &ahci_imx_pm_ops, }, }; module_platform_driver(imx_ahci_driver); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 4b231baceb09..ef67e79944f9 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -12,135 +12,36 @@ * any later version. */ -#include <linux/clk.h> #include <linux/kernel.h> -#include <linux/gfp.h> #include <linux/module.h> #include <linux/pm.h> -#include <linux/init.h> -#include <linux/interrupt.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/libata.h> #include <linux/ahci_platform.h> #include "ahci.h" -static void ahci_host_stop(struct ata_host *host); - -enum ahci_type { - AHCI, /* standard platform ahci */ - IMX53_AHCI, /* ahci on i.mx53 */ - STRICT_AHCI, /* delayed DMA engine start */ -}; - -static struct platform_device_id ahci_devtype[] = { - { - .name = "ahci", - .driver_data = AHCI, - }, { - .name = "imx53-ahci", - .driver_data = IMX53_AHCI, - }, { - .name = "strict-ahci", - .driver_data = STRICT_AHCI, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, ahci_devtype); - -struct ata_port_operations ahci_platform_ops = { - .inherits = &ahci_ops, - .host_stop = ahci_host_stop, -}; -EXPORT_SYMBOL_GPL(ahci_platform_ops); - -static struct ata_port_operations ahci_platform_retry_srst_ops = { - .inherits = &ahci_pmp_retry_srst_ops, - .host_stop = ahci_host_stop, -}; - -static const struct ata_port_info ahci_port_info[] = { - /* by features */ - [AHCI] = { - .flags = AHCI_FLAG_COMMON, - .pio_mask = ATA_PIO4, - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_platform_ops, - }, - [IMX53_AHCI] = { - .flags = AHCI_FLAG_COMMON, - .pio_mask = ATA_PIO4, - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_platform_retry_srst_ops, - }, - [STRICT_AHCI] = { - AHCI_HFLAGS (AHCI_HFLAG_DELAY_ENGINE), - .flags = AHCI_FLAG_COMMON, - .pio_mask = ATA_PIO4, - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_platform_ops, - }, -}; - -static struct scsi_host_template ahci_platform_sht = { - AHCI_SHT("ahci_platform"), +static const struct ata_port_info ahci_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, }; static int ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_platform_data *pdata = dev_get_platdata(dev); - const struct platform_device_id *id = platform_get_device_id(pdev); - struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0]; - const struct ata_port_info *ppi[] = { &pi, NULL }; struct ahci_host_priv *hpriv; - struct ata_host *host; - struct resource *mem; - int irq; - int n_ports; - int i; int rc; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(dev, "no mmio space\n"); - return -EINVAL; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(dev, "no irq\n"); - return -EINVAL; - } - - if (pdata && pdata->ata_port_info) - pi = *pdata->ata_port_info; - - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - dev_err(dev, "can't alloc ahci_host_priv\n"); - return -ENOMEM; - } - - hpriv->flags |= (unsigned long)pi.private_data; - - hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); - if (!hpriv->mmio) { - dev_err(dev, "can't map %pR\n", mem); - return -ENOMEM; - } + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); - hpriv->clk = clk_get(dev, NULL); - if (IS_ERR(hpriv->clk)) { - dev_err(dev, "can't get clock\n"); - } else { - rc = clk_prepare_enable(hpriv->clk); - if (rc) { - dev_err(dev, "clock prepare enable failed"); - goto free_clk; - } - } + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; /* * Some platforms might need to prepare for mmio region access, @@ -151,69 +52,10 @@ static int ahci_probe(struct platform_device *pdev) if (pdata && pdata->init) { rc = pdata->init(dev, hpriv->mmio); if (rc) - goto disable_unprepare_clk; - } - - ahci_save_initial_config(dev, hpriv, - pdata ? pdata->force_port_map : 0, - pdata ? pdata->mask_port_map : 0); - - /* prepare host */ - if (hpriv->cap & HOST_CAP_NCQ) - pi.flags |= ATA_FLAG_NCQ; - - if (hpriv->cap & HOST_CAP_PMP) - pi.flags |= ATA_FLAG_PMP; - - ahci_set_em_messages(hpriv, &pi); - - /* CAP.NP sometimes indicate the index of the last enabled - * port, at other times, that of the last possible port, so - * determining the maximum port number requires looking at - * both CAP.NP and port_map. - */ - n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); - - host = ata_host_alloc_pinfo(dev, ppi, n_ports); - if (!host) { - rc = -ENOMEM; - goto pdata_exit; - } - - host->private_data = hpriv; - - if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) - host->flags |= ATA_HOST_PARALLEL_SCAN; - else - dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); - - if (pi.flags & ATA_FLAG_EM) - ahci_reset_em(host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - ata_port_desc(ap, "mmio %pR", mem); - ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); - - /* set enclosure management message type */ - if (ap->flags & ATA_FLAG_EM) - ap->em_message_type = hpriv->em_msg_type; - - /* disabled/not-implemented port */ - if (!(hpriv->port_map & (1 << i))) - ap->ops = &ata_dummy_port_ops; + goto disable_resources; } - rc = ahci_reset_controller(host); - if (rc) - goto pdata_exit; - - ahci_init_controller(host); - ahci_print_info(host, "platform"); - - rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, - &ahci_platform_sht); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0); if (rc) goto pdata_exit; @@ -221,115 +63,19 @@ static int ahci_probe(struct platform_device *pdev) pdata_exit: if (pdata && pdata->exit) pdata->exit(dev); -disable_unprepare_clk: - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); -free_clk: - if (!IS_ERR(hpriv->clk)) - clk_put(hpriv->clk); - return rc; -} - -static void ahci_host_stop(struct ata_host *host) -{ - struct device *dev = host->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); - struct ahci_host_priv *hpriv = host->private_data; - - if (pdata && pdata->exit) - pdata->exit(dev); - - if (!IS_ERR(hpriv->clk)) { - clk_disable_unprepare(hpriv->clk); - clk_put(hpriv->clk); - } -} - -#ifdef CONFIG_PM_SLEEP -static int ahci_suspend(struct device *dev) -{ - struct ahci_platform_data *pdata = dev_get_platdata(dev); - struct ata_host *host = dev_get_drvdata(dev); - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = hpriv->mmio; - u32 ctl; - int rc; - - if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { - dev_err(dev, "firmware update required for suspend/resume\n"); - return -EIO; - } - - /* - * AHCI spec rev1.1 section 8.3.3: - * Software must disable interrupts prior to requesting a - * transition of the HBA to D3 state. - */ - ctl = readl(mmio + HOST_CTL); - ctl &= ~HOST_IRQ_EN; - writel(ctl, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - - rc = ata_host_suspend(host, PMSG_SUSPEND); - if (rc) - return rc; - - if (pdata && pdata->suspend) - return pdata->suspend(dev); - - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); - - return 0; -} - -static int ahci_resume(struct device *dev) -{ - struct ahci_platform_data *pdata = dev_get_platdata(dev); - struct ata_host *host = dev_get_drvdata(dev); - struct ahci_host_priv *hpriv = host->private_data; - int rc; - - if (!IS_ERR(hpriv->clk)) { - rc = clk_prepare_enable(hpriv->clk); - if (rc) { - dev_err(dev, "clock prepare enable failed"); - return rc; - } - } - - if (pdata && pdata->resume) { - rc = pdata->resume(dev); - if (rc) - goto disable_unprepare_clk; - } - - if (dev->power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_reset_controller(host); - if (rc) - goto disable_unprepare_clk; - - ahci_init_controller(host); - } - - ata_host_resume(host); - - return 0; - -disable_unprepare_clk: - if (!IS_ERR(hpriv->clk)) - clk_disable_unprepare(hpriv->clk); - +disable_resources: + ahci_platform_disable_resources(hpriv); return rc; } -#endif -static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); +static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, + ahci_platform_resume); static const struct of_device_id ahci_of_match[] = { { .compatible = "snps,spear-ahci", }, { .compatible = "snps,exynos5440-ahci", }, { .compatible = "ibm,476gtr-ahci", }, + { .compatible = "snps,dwc-ahci", }, {}, }; MODULE_DEVICE_TABLE(of, ahci_of_match); @@ -343,7 +89,6 @@ static struct platform_driver ahci_driver = { .of_match_table = ahci_of_match, .pm = &ahci_pm_ops, }, - .id_table = ahci_devtype, }; module_platform_driver(ahci_driver); diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c new file mode 100644 index 000000000000..633222226c19 --- /dev/null +++ b/drivers/ata/ahci_st.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2012 STMicroelectronics Limited + * + * Authors: Francesco Virlinzi <francesco.virlinzi@st.com> + * Alexandre Torgue <alexandre.torgue@st.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/export.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/ahci_platform.h> +#include <linux/libata.h> +#include <linux/reset.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> + +#include "ahci.h" + +#define ST_AHCI_OOBR 0xbc +#define ST_AHCI_OOBR_WE BIT(31) +#define ST_AHCI_OOBR_CWMIN_SHIFT 24 +#define ST_AHCI_OOBR_CWMAX_SHIFT 16 +#define ST_AHCI_OOBR_CIMIN_SHIFT 8 +#define ST_AHCI_OOBR_CIMAX_SHIFT 0 + +struct st_ahci_drv_data { + struct platform_device *ahci; + struct reset_control *pwr; + struct reset_control *sw_rst; + struct reset_control *pwr_rst; + struct ahci_host_priv *hpriv; +}; + +static void st_ahci_configure_oob(void __iomem *mmio) +{ + unsigned long old_val, new_val; + + new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) | + (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) | + (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) | + (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT); + + old_val = readl(mmio + ST_AHCI_OOBR); + writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); + writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); + writel(new_val, mmio + ST_AHCI_OOBR); +} + +static int st_ahci_deassert_resets(struct device *dev) +{ + struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); + int err; + + if (drv_data->pwr) { + err = reset_control_deassert(drv_data->pwr); + if (err) { + dev_err(dev, "unable to bring out of pwrdwn\n"); + return err; + } + } + + st_ahci_configure_oob(drv_data->hpriv->mmio); + + if (drv_data->sw_rst) { + err = reset_control_deassert(drv_data->sw_rst); + if (err) { + dev_err(dev, "unable to bring out of sw-rst\n"); + return err; + } + } + + if (drv_data->pwr_rst) { + err = reset_control_deassert(drv_data->pwr_rst); + if (err) { + dev_err(dev, "unable to bring out of pwr-rst\n"); + return err; + } + } + + return 0; +} + +static void st_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + struct device *dev = host->dev; + struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); + int err; + + if (drv_data->pwr) { + err = reset_control_assert(drv_data->pwr); + if (err) + dev_err(dev, "unable to pwrdwn\n"); + } + + ahci_platform_disable_resources(hpriv); +} + +static int st_ahci_probe_resets(struct platform_device *pdev) +{ + struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev); + + drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn"); + if (IS_ERR(drv_data->pwr)) { + dev_info(&pdev->dev, "power reset control not defined\n"); + drv_data->pwr = NULL; + } + + drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst"); + if (IS_ERR(drv_data->sw_rst)) { + dev_info(&pdev->dev, "soft reset control not defined\n"); + drv_data->sw_rst = NULL; + } + + drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst"); + if (IS_ERR(drv_data->pwr_rst)) { + dev_dbg(&pdev->dev, "power soft reset control not defined\n"); + drv_data->pwr_rst = NULL; + } + + return st_ahci_deassert_resets(&pdev->dev); +} + +static struct ata_port_operations st_ahci_port_ops = { + .inherits = &ahci_platform_ops, + .host_stop = st_ahci_host_stop, +}; + +static const struct ata_port_info st_ahci_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &st_ahci_port_ops, +}; + +static int st_ahci_probe(struct platform_device *pdev) +{ + struct st_ahci_drv_data *drv_data; + struct ahci_host_priv *hpriv; + int err; + + drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + platform_set_drvdata(pdev, drv_data); + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + drv_data->hpriv = hpriv; + + err = st_ahci_probe_resets(pdev); + if (err) + return err; + + err = ahci_platform_enable_resources(hpriv); + if (err) + return err; + + err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0); + if (err) { + ahci_platform_disable_resources(hpriv); + return err; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int st_ahci_suspend(struct device *dev) +{ + struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = drv_data->hpriv; + int err; + + err = ahci_platform_suspend_host(dev); + if (err) + return err; + + if (drv_data->pwr) { + err = reset_control_assert(drv_data->pwr); + if (err) { + dev_err(dev, "unable to pwrdwn"); + return err; + } + } + + ahci_platform_disable_resources(hpriv); + + return 0; +} + +static int st_ahci_resume(struct device *dev) +{ + struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = drv_data->hpriv; + int err; + + err = ahci_platform_enable_resources(hpriv); + if (err) + return err; + + err = st_ahci_deassert_resets(dev); + if (err) { + ahci_platform_disable_resources(hpriv); + return err; + } + + return ahci_platform_resume_host(dev); +} +#endif + +static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume); + +static struct of_device_id st_ahci_match[] = { + { .compatible = "st,ahci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_ahci_match); + +static struct platform_driver st_ahci_driver = { + .driver = { + .name = "st_ahci", + .owner = THIS_MODULE, + .pm = &st_ahci_pm_ops, + .of_match_table = of_match_ptr(st_ahci_match), + }, + .probe = st_ahci_probe, + .remove = ata_platform_remove_one, +}; +module_platform_driver(st_ahci_driver); + +MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>"); +MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c new file mode 100644 index 000000000000..42d3f64e74b3 --- /dev/null +++ b/drivers/ata/ahci_sunxi.c @@ -0,0 +1,249 @@ +/* + * Allwinner sunxi AHCI SATA platform driver + * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl> + * Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * + * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov + * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>, + * Daniel Wang <danielwang@allwinnertech.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/ahci_platform.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include "ahci.h" + +#define AHCI_BISTAFR 0x00a0 +#define AHCI_BISTCR 0x00a4 +#define AHCI_BISTFCTR 0x00a8 +#define AHCI_BISTSR 0x00ac +#define AHCI_BISTDECR 0x00b0 +#define AHCI_DIAGNR0 0x00b4 +#define AHCI_DIAGNR1 0x00b8 +#define AHCI_OOBR 0x00bc +#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8 +#define AHCI_TIMER1MS 0x00e0 +#define AHCI_GPARAM1R 0x00e8 +#define AHCI_GPARAM2R 0x00ec +#define AHCI_PPARAMR 0x00f0 +#define AHCI_TESTR 0x00f4 +#define AHCI_VERSIONR 0x00f8 +#define AHCI_IDR 0x00fc +#define AHCI_RWCR 0x00fc +#define AHCI_P0DMACR 0x0170 +#define AHCI_P0PHYCR 0x0178 +#define AHCI_P0PHYSR 0x017c + +static void sunxi_clrbits(void __iomem *reg, u32 clr_val) +{ + u32 reg_val; + + reg_val = readl(reg); + reg_val &= ~(clr_val); + writel(reg_val, reg); +} + +static void sunxi_setbits(void __iomem *reg, u32 set_val) +{ + u32 reg_val; + + reg_val = readl(reg); + reg_val |= set_val; + writel(reg_val, reg); +} + +static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val) +{ + u32 reg_val; + + reg_val = readl(reg); + reg_val &= ~(clr_val); + reg_val |= set_val; + writel(reg_val, reg); +} + +static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift) +{ + return (readl(reg) >> shift) & mask; +} + +static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base) +{ + u32 reg_val; + int timeout; + + /* This magic is from the original code */ + writel(0, reg_base + AHCI_RWCR); + msleep(5); + + sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19)); + sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, + (0x7 << 24), + (0x5 << 24) | BIT(23) | BIT(18)); + sunxi_clrsetbits(reg_base + AHCI_PHYCS1R, + (0x3 << 16) | (0x1f << 8) | (0x3 << 6), + (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); + sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15)); + sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19)); + sunxi_clrsetbits(reg_base + AHCI_PHYCS0R, + (0x7 << 20), (0x3 << 20)); + sunxi_clrsetbits(reg_base + AHCI_PHYCS2R, + (0x1f << 5), (0x19 << 5)); + msleep(5); + + sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19)); + + timeout = 250; /* Power up takes aprox 50 us */ + do { + reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28); + if (reg_val == 0x02) + break; + + if (--timeout == 0) { + dev_err(dev, "PHY power up failed.\n"); + return -EIO; + } + udelay(1); + } while (1); + + sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24)); + + timeout = 100; /* Calibration takes aprox 10 us */ + do { + reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24); + if (reg_val == 0x00) + break; + + if (--timeout == 0) { + dev_err(dev, "PHY calibration failed.\n"); + return -EIO; + } + udelay(1); + } while (1); + + msleep(15); + + writel(0x7, reg_base + AHCI_RWCR); + + return 0; +} + +static void ahci_sunxi_start_engine(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_host_priv *hpriv = ap->host->private_data; + + /* Setup DMA before DMA start */ + sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400); + + /* Start DMA */ + sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START); +} + +static const struct ata_port_info ahci_sunxi_port_info = { + AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | + AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static int ahci_sunxi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + hpriv->start_engine = ahci_sunxi_start_engine; + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + rc = ahci_sunxi_phy_init(dev, hpriv->mmio); + if (rc) + goto disable_resources; + + rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0); + if (rc) + goto disable_resources; + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +#ifdef CONFIG_PM_SLEEP +static int ahci_sunxi_resume(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + rc = ahci_sunxi_phy_init(dev, hpriv->mmio); + if (rc) + goto disable_resources; + + rc = ahci_platform_resume_host(dev); + if (rc) + goto disable_resources; + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} +#endif + +static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend, + ahci_sunxi_resume); + +static const struct of_device_id ahci_sunxi_of_match[] = { + { .compatible = "allwinner,sun4i-a10-ahci", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match); + +static struct platform_driver ahci_sunxi_driver = { + .probe = ahci_sunxi_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "ahci-sunxi", + .owner = THIS_MODULE, + .of_match_table = ahci_sunxi_of_match, + .pm = &ahci_sunxi_pm_ops, + }, +}; +module_platform_driver(ahci_sunxi_driver); + +MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver"); +MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c new file mode 100644 index 000000000000..77c89bf171f1 --- /dev/null +++ b/drivers/ata/ahci_xgene.c @@ -0,0 +1,486 @@ +/* + * AppliedMicro X-Gene SoC SATA Host Controller Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Loc Ho <lho@apm.com> + * Tuan Phan <tphan@apm.com> + * Suman Tripathi <stripathi@apm.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * NOTE: PM support is not currently available. + * + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/ahci_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/phy/phy.h> +#include "ahci.h" + +/* Max # of disk per a controller */ +#define MAX_AHCI_CHN_PERCTR 2 + +/* MUX CSR */ +#define SATA_ENET_CONFIG_REG 0x00000000 +#define CFG_SATA_ENET_SELECT_MASK 0x00000001 + +/* SATA core host controller CSR */ +#define SLVRDERRATTRIBUTES 0x00000000 +#define SLVWRERRATTRIBUTES 0x00000004 +#define MSTRDERRATTRIBUTES 0x00000008 +#define MSTWRERRATTRIBUTES 0x0000000c +#define BUSCTLREG 0x00000014 +#define IOFMSTRWAUX 0x00000018 +#define INTSTATUSMASK 0x0000002c +#define ERRINTSTATUS 0x00000030 +#define ERRINTSTATUSMASK 0x00000034 + +/* SATA host AHCI CSR */ +#define PORTCFG 0x000000a4 +#define PORTADDR_SET(dst, src) \ + (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f)) +#define PORTPHY1CFG 0x000000a8 +#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \ + (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000)) +#define PORTPHY2CFG 0x000000ac +#define PORTPHY3CFG 0x000000b0 +#define PORTPHY4CFG 0x000000b4 +#define PORTPHY5CFG 0x000000b8 +#define SCTL0 0x0000012C +#define PORTPHY5CFG_RTCHG_SET(dst, src) \ + (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000)) +#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \ + (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000)) +#define PORTAXICFG 0x000000bc +#define PORTAXICFG_OUTTRANS_SET(dst, src) \ + (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000)) + +/* SATA host controller AXI CSR */ +#define INT_SLV_TMOMASK 0x00000010 + +/* SATA diagnostic CSR */ +#define CFG_MEM_RAM_SHUTDOWN 0x00000070 +#define BLOCK_MEM_RDY 0x00000074 + +struct xgene_ahci_context { + struct ahci_host_priv *hpriv; + struct device *dev; + void __iomem *csr_core; /* Core CSR address of IP */ + void __iomem *csr_diag; /* Diag CSR address of IP */ + void __iomem *csr_axi; /* AXI CSR address of IP */ + void __iomem *csr_mux; /* MUX CSR address of IP */ +}; + +static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) +{ + dev_dbg(ctx->dev, "Release memory from shutdown\n"); + writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); + readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */ + msleep(1); /* reset may take up to 1ms */ + if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) { + dev_err(ctx->dev, "failed to release memory from shutdown\n"); + return -ENODEV; + } + return 0; +} + +/** + * xgene_ahci_read_id - Read ID data from the specified device + * @dev: device + * @tf: proposed taskfile + * @id: data buffer + * + * This custom read ID function is required due to the fact that the HW + * does not support DEVSLP and the controller state machine may get stuck + * after processing the ID query command. + */ +static unsigned int xgene_ahci_read_id(struct ata_device *dev, + struct ata_taskfile *tf, u16 *id) +{ + u32 err_mask; + void __iomem *port_mmio = ahci_port_base(dev->link->ap); + + err_mask = ata_do_dev_read_id(dev, tf, id); + if (err_mask) + return err_mask; + + /* + * Mask reserved area. Word78 spec of Link Power Management + * bit15-8: reserved + * bit7: NCQ autosence + * bit6: Software settings preservation supported + * bit5: reserved + * bit4: In-order sata delivery supported + * bit3: DIPM requests supported + * bit2: DMA Setup FIS Auto-Activate optimization supported + * bit1: DMA Setup FIX non-Zero buffer offsets supported + * bit0: Reserved + * + * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP + */ + id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); + + /* + * Due to HW errata, restart the port if no other command active. + * Otherwise the controller may get stuck. + */ + if (!readl(port_mmio + PORT_CMD_ISSUE)) { + writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* Force a barrier */ + writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* Force a barrier */ + } + return 0; +} + +static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) +{ + void __iomem *mmio = ctx->hpriv->mmio; + u32 val; + + dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n", + mmio, channel); + val = readl(mmio + PORTCFG); + val = PORTADDR_SET(val, channel == 0 ? 2 : 3); + writel(val, mmio + PORTCFG); + readl(mmio + PORTCFG); /* Force a barrier */ + /* Disable fix rate */ + writel(0x0001fffe, mmio + PORTPHY1CFG); + readl(mmio + PORTPHY1CFG); /* Force a barrier */ + writel(0x5018461c, mmio + PORTPHY2CFG); + readl(mmio + PORTPHY2CFG); /* Force a barrier */ + writel(0x1c081907, mmio + PORTPHY3CFG); + readl(mmio + PORTPHY3CFG); /* Force a barrier */ + writel(0x1c080815, mmio + PORTPHY4CFG); + readl(mmio + PORTPHY4CFG); /* Force a barrier */ + /* Set window negotiation */ + val = readl(mmio + PORTPHY5CFG); + val = PORTPHY5CFG_RTCHG_SET(val, 0x300); + writel(val, mmio + PORTPHY5CFG); + readl(mmio + PORTPHY5CFG); /* Force a barrier */ + val = readl(mmio + PORTAXICFG); + val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */ + val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */ + writel(val, mmio + PORTAXICFG); + readl(mmio + PORTAXICFG); /* Force a barrier */ +} + +/** + * xgene_ahci_do_hardreset - Issue the actual COMRESET + * @link: link to reset + * @deadline: deadline jiffies for the operation + * @online: Return value to indicate if device online + * + * Due to the limitation of the hardware PHY, a difference set of setting is + * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps), + * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will + * report disparity error and etc. In addition, during COMRESET, there can + * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and + * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following + * algorithm is followed to proper configure the hardware PHY during COMRESET: + * + * Alg Part 1: + * 1. Start the PHY at Gen3 speed (default setting) + * 2. Issue the COMRESET + * 3. If no link, go to Alg Part 3 + * 4. If link up, determine if the negotiated speed matches the PHY + * configured speed + * 5. If they matched, go to Alg Part 2 + * 6. If they do not matched and first time, configure the PHY for the linked + * up disk speed and repeat step 2 + * 7. Go to Alg Part 2 + * + * Alg Part 2: + * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error + * reported in the register PORT_SCR_ERR, then reset the PHY receiver line + * 2. Go to Alg Part 3 + * + * Alg Part 3: + * 1. Clear any pending from register PORT_SCR_ERR. + * + * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition + * and until the underlying PHY supports an method to reset the receiver + * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors, + * an warning message will be printed. + */ +static int xgene_ahci_do_hardreset(struct ata_link *link, + unsigned long deadline, bool *online) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + struct xgene_ahci_context *ctx = hpriv->plat_data; + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + void __iomem *port_mmio = ahci_port_base(ap); + struct ata_taskfile tf; + int rc; + u32 val; + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = ATA_BUSY; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + rc = sata_link_hardreset(link, timing, deadline, online, + ahci_check_ready); + + val = readl(port_mmio + PORT_SCR_ERR); + if (val & (SERR_DISPARITY | SERR_10B_8B_ERR)) + dev_warn(ctx->dev, "link has error\n"); + + /* clear all errors if any pending */ + val = readl(port_mmio + PORT_SCR_ERR); + writel(val, port_mmio + PORT_SCR_ERR); + + return rc; +} + +static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + bool online; + int rc; + u32 portcmd_saved; + u32 portclb_saved; + u32 portclbhi_saved; + u32 portrxfis_saved; + u32 portrxfishi_saved; + + /* As hardreset resets these CSR, save it to restore later */ + portcmd_saved = readl(port_mmio + PORT_CMD); + portclb_saved = readl(port_mmio + PORT_LST_ADDR); + portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI); + portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); + portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); + + ahci_stop_engine(ap); + + rc = xgene_ahci_do_hardreset(link, deadline, &online); + + /* As controller hardreset clears them, restore them */ + writel(portcmd_saved, port_mmio + PORT_CMD); + writel(portclb_saved, port_mmio + PORT_LST_ADDR); + writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI); + writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR); + writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI); + + hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + return rc; +} + +static void xgene_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + + ahci_platform_disable_resources(hpriv); +} + +static struct ata_port_operations xgene_ahci_ops = { + .inherits = &ahci_ops, + .host_stop = xgene_ahci_host_stop, + .hardreset = xgene_ahci_hardreset, + .read_id = xgene_ahci_read_id, +}; + +static const struct ata_port_info xgene_ahci_port_info = { + AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &xgene_ahci_ops, +}; + +static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) +{ + struct xgene_ahci_context *ctx = hpriv->plat_data; + int i; + int rc; + u32 val; + + /* Remove IP RAM out of shutdown */ + rc = xgene_ahci_init_memram(ctx); + if (rc) + return rc; + + for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++) + xgene_ahci_set_phy_cfg(ctx, i); + + /* AXI disable Mask */ + writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT); + readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */ + writel(0, ctx->csr_core + INTSTATUSMASK); + val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */ + dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n", + INTSTATUSMASK, val); + + writel(0x0, ctx->csr_core + ERRINTSTATUSMASK); + readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */ + writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK); + readl(ctx->csr_axi + INT_SLV_TMOMASK); + + /* Enable AXI Interrupt */ + writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES); + writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES); + + /* Enable coherency */ + val = readl(ctx->csr_core + BUSCTLREG); + val &= ~0x00000002; /* Enable write coherency */ + val &= ~0x00000001; /* Enable read coherency */ + writel(val, ctx->csr_core + BUSCTLREG); + + val = readl(ctx->csr_core + IOFMSTRWAUX); + val |= (1 << 3); /* Enable read coherency */ + val |= (1 << 9); /* Enable write coherency */ + writel(val, ctx->csr_core + IOFMSTRWAUX); + val = readl(ctx->csr_core + IOFMSTRWAUX); + dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n", + IOFMSTRWAUX, val); + + return rc; +} + +static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) +{ + u32 val; + + /* Check for optional MUX resource */ + if (IS_ERR(ctx->csr_mux)) + return 0; + + val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); + val &= ~CFG_SATA_ENET_SELECT_MASK; + writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG); + val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); + return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0; +} + +static int xgene_ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct xgene_ahci_context *ctx; + struct resource *res; + int rc; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + hpriv->plat_data = ctx; + ctx->hpriv = hpriv; + ctx->dev = dev; + + /* Retrieve the IP core resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ctx->csr_core = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_core)) + return PTR_ERR(ctx->csr_core); + + /* Retrieve the IP diagnostic resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + ctx->csr_diag = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_diag)) + return PTR_ERR(ctx->csr_diag); + + /* Retrieve the IP AXI resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 3); + ctx->csr_axi = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->csr_axi)) + return PTR_ERR(ctx->csr_axi); + + /* Retrieve the optional IP mux resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 4); + ctx->csr_mux = devm_ioremap_resource(dev, res); + + dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, + hpriv->mmio); + + /* Select ATA */ + if ((rc = xgene_ahci_mux_select(ctx))) { + dev_err(dev, "SATA mux selection failed error %d\n", rc); + return -ENODEV; + } + + /* Due to errata, HW requires full toggle transition */ + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_resources; + ahci_platform_disable_clks(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + goto disable_resources; + + /* Configure the host controller */ + xgene_ahci_hw_init(hpriv); + + /* + * Setup DMA mask. This is preliminary until the DMA range is sorted + * out. + */ + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(dev, "Unable to set dma mask\n"); + goto disable_resources; + } + + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0); + if (rc) + goto disable_resources; + + dev_dbg(dev, "X-Gene SATA host controller initialized\n"); + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +static const struct of_device_id xgene_ahci_of_match[] = { + {.compatible = "apm,xgene-ahci"}, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); + +static struct platform_driver xgene_ahci_driver = { + .probe = xgene_ahci_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = "xgene-ahci", + .owner = THIS_MODULE, + .of_match_table = xgene_ahci_of_match, + }, +}; + +module_platform_driver(xgene_ahci_driver); + +MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver"); +MODULE_AUTHOR("Loc Ho <lho@apm.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.4"); diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 7d196656adb5..9498a7d3846f 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 36605abe5a67..6bd4f660b4e1 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -394,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev, * * If inconsistent, config values are fixed up by this function. * + * If it is not set already this function sets hpriv->start_engine to + * ahci_start_engine. + * * LOCKING: * None. */ @@ -500,6 +502,9 @@ void ahci_save_initial_config(struct device *dev, hpriv->cap = cap; hpriv->cap2 = cap2; hpriv->port_map = port_map; + + if (!hpriv->start_engine) + hpriv->start_engine = ahci_start_engine; } EXPORT_SYMBOL_GPL(ahci_save_initial_config); @@ -766,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap) /* enable DMA */ if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) - ahci_start_engine(ap); + hpriv->start_engine(ap); /* turn on LEDs */ if (ap->flags & ATA_FLAG_EM) { @@ -1032,12 +1037,13 @@ 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) { - int state; + unsigned int state; int pmp; struct ahci_port_priv *pp = ap->private_data; struct ahci_em_priv *emp; - state = simple_strtoul(buf, NULL, 0); + if (kstrtouint(buf, 0, &state) < 0) + return -EINVAL; /* get the slot number from the message */ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; @@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap) /* restart engine */ out_restart: - ahci_start_engine(ap); + hpriv->start_engine(ap); return rc; } EXPORT_SYMBOL_GPL(ahci_kick_engine); @@ -1387,8 +1393,8 @@ static int ahci_bad_pmp_check_ready(struct ata_link *link) return ata_check_ready(status); } -int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { struct ata_port *ap = link->ap; void __iomem *port_mmio = ahci_port_base(ap); @@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, rc = sata_link_hardreset(link, timing, deadline, &online, ahci_check_ready); - ahci_start_engine(ap); + hpriv->start_engine(ap); if (online) *class = ahci_dev_classify(ap); @@ -1629,7 +1636,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) } if (irq_stat & PORT_IRQ_UNK_FIS) { - u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); + u32 *unk = pp->rx_fis + RX_FIS_UNK; active_ehi->err_mask |= AC_ERR_HSM; active_ehi->action |= ATA_EH_RESET; @@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap) void ahci_error_handler(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ ahci_stop_engine(ap); - ahci_start_engine(ap); + hpriv->start_engine(ap); } sata_pmp_error_handler(ap); @@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) { + struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); struct ata_device *dev = ap->link.device; u32 devslp, dm, dito, mdat, deto; @@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) PORT_DEVSLP_ADSE); writel(devslp, port_mmio + PORT_DEVSLP); - ahci_start_engine(ap); + hpriv->start_engine(ap); /* enable device sleep feature for the drive */ err_mask = ata_dev_set_feature(dev, @@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) static void ahci_enable_fbs(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); u32 fbs; @@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap) } else dev_err(ap->host->dev, "Failed to enable FBS\n"); - ahci_start_engine(ap); + hpriv->start_engine(ap); } static void ahci_disable_fbs(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); u32 fbs; @@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap) pp->fbs_enabled = false; } - ahci_start_engine(ap); + hpriv->start_engine(ap); } static void ahci_pmp_attach(struct ata_port *ap) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c new file mode 100644 index 000000000000..7cb3a85719c0 --- /dev/null +++ b/drivers/ata/libahci_platform.c @@ -0,0 +1,541 @@ +/* + * AHCI SATA platform library + * + * Copyright 2004-2005 Red Hat, Inc. + * Jeff Garzik <jgarzik@pobox.com> + * Copyright 2010 MontaVista Software, LLC. + * Anton Vorontsov <avorontsov@ru.mvista.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/libata.h> +#include <linux/ahci_platform.h> +#include <linux/phy/phy.h> +#include <linux/pm_runtime.h> +#include "ahci.h" + +static void ahci_host_stop(struct ata_host *host); + +struct ata_port_operations ahci_platform_ops = { + .inherits = &ahci_ops, + .host_stop = ahci_host_stop, +}; +EXPORT_SYMBOL_GPL(ahci_platform_ops); + +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT("ahci_platform"), +}; + +/** + * ahci_platform_enable_clks - Enable platform clocks + * @hpriv: host private area to store config values + * + * This function enables all the clks found in hpriv->clks, starting at + * index 0. If any clk fails to enable it disables all the clks already + * enabled in reverse order, and then returns an error. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) +{ + int c, rc; + + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) { + rc = clk_prepare_enable(hpriv->clks[c]); + if (rc) + goto disable_unprepare_clk; + } + return 0; + +disable_unprepare_clk: + while (--c >= 0) + clk_disable_unprepare(hpriv->clks[c]); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); + +/** + * ahci_platform_disable_clks - Disable platform clocks + * @hpriv: host private area to store config values + * + * This function disables all the clks found in hpriv->clks, in reverse + * order of ahci_platform_enable_clks (starting at the end of the array). + */ +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) +{ + int c; + + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--) + if (hpriv->clks[c]) + clk_disable_unprepare(hpriv->clks[c]); +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); + +/** + * ahci_platform_enable_resources - Enable platform resources + * @hpriv: host private area to store config values + * + * This function enables all ahci_platform managed resources in the + * following order: + * 1) Regulator + * 2) Clocks (through ahci_platform_enable_clks) + * 3) Phy + * + * If resource enabling fails at any point the previous enabled resources + * are disabled in reverse order. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) +{ + int rc; + + if (hpriv->target_pwr) { + rc = regulator_enable(hpriv->target_pwr); + if (rc) + return rc; + } + + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_regulator; + + if (hpriv->phy) { + rc = phy_init(hpriv->phy); + if (rc) + goto disable_clks; + + rc = phy_power_on(hpriv->phy); + if (rc) { + phy_exit(hpriv->phy); + goto disable_clks; + } + } + + return 0; + +disable_clks: + ahci_platform_disable_clks(hpriv); + +disable_regulator: + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); + +/** + * ahci_platform_disable_resources - Disable platform resources + * @hpriv: host private area to store config values + * + * This function disables all ahci_platform managed resources in the + * following order: + * 1) Phy + * 2) Clocks (through ahci_platform_disable_clks) + * 3) Regulator + */ +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) +{ + if (hpriv->phy) { + phy_power_off(hpriv->phy); + phy_exit(hpriv->phy); + } + + ahci_platform_disable_clks(hpriv); + + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); + +static void ahci_platform_put_resources(struct device *dev, void *res) +{ + struct ahci_host_priv *hpriv = res; + int c; + + if (hpriv->got_runtime_pm) { + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + } + + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) + clk_put(hpriv->clks[c]); +} + +/** + * ahci_platform_get_resources - Get platform resources + * @pdev: platform device to get resources for + * + * This function allocates an ahci_host_priv struct, and gets the following + * resources, storing a reference to them inside the returned struct: + * + * 1) mmio registers (IORESOURCE_MEM 0, mandatory) + * 2) regulator for controlling the targets power (optional) + * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, + * or for non devicetree enabled platforms a single clock + * 4) phy (optional) + * + * RETURNS: + * The allocated ahci_host_priv on success, otherwise an ERR_PTR value + */ +struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct clk *clk; + int i, rc = -ENOMEM; + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return ERR_PTR(-ENOMEM); + + hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), + GFP_KERNEL); + if (!hpriv) + goto err_out; + + devres_add(dev, hpriv); + + hpriv->mmio = devm_ioremap_resource(dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + if (IS_ERR(hpriv->mmio)) { + dev_err(dev, "no mmio space\n"); + rc = PTR_ERR(hpriv->mmio); + goto err_out; + } + + hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); + if (IS_ERR(hpriv->target_pwr)) { + rc = PTR_ERR(hpriv->target_pwr); + if (rc == -EPROBE_DEFER) + goto err_out; + hpriv->target_pwr = NULL; + } + + for (i = 0; i < AHCI_MAX_CLKS; i++) { + /* + * For now we must use clk_get(dev, NULL) for the first clock, + * because some platforms (da850, spear13xx) are not yet + * converted to use devicetree for clocks. For new platforms + * this is equivalent to of_clk_get(dev->of_node, 0). + */ + if (i == 0) + clk = clk_get(dev, NULL); + else + clk = of_clk_get(dev->of_node, i); + + if (IS_ERR(clk)) { + rc = PTR_ERR(clk); + if (rc == -EPROBE_DEFER) + goto err_out; + break; + } + hpriv->clks[i] = clk; + } + + hpriv->phy = devm_phy_get(dev, "sata-phy"); + if (IS_ERR(hpriv->phy)) { + rc = PTR_ERR(hpriv->phy); + switch (rc) { + case -ENODEV: + case -ENOSYS: + /* continue normally */ + hpriv->phy = NULL; + break; + + case -EPROBE_DEFER: + goto err_out; + + default: + dev_err(dev, "couldn't get sata-phy\n"); + goto err_out; + } + } + + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + hpriv->got_runtime_pm = true; + + devres_remove_group(dev, NULL); + return hpriv; + +err_out: + devres_release_group(dev, NULL); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(ahci_platform_get_resources); + +/** + * ahci_platform_init_host - Bring up an ahci-platform host + * @pdev: platform device pointer for the host + * @hpriv: ahci-host private data for the host + * @pi_template: template for the ata_port_info to use + * @force_port_map: param passed to ahci_save_initial_config + * @mask_port_map: param passed to ahci_save_initial_config + * + * This function does all the usual steps needed to bring up an + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * must be initialized / enabled before calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_init_host(struct platform_device *pdev, + struct ahci_host_priv *hpriv, + const struct ata_port_info *pi_template, + unsigned int force_port_map, + unsigned int mask_port_map) +{ + struct device *dev = &pdev->dev; + struct ata_port_info pi = *pi_template; + const struct ata_port_info *ppi[] = { &pi, NULL }; + struct ata_host *host; + int i, irq, n_ports, rc; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "no irq\n"); + return -EINVAL; + } + + /* prepare host */ + hpriv->flags |= (unsigned long)pi.private_data; + + ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); + + if (hpriv->cap & HOST_CAP_NCQ) + pi.flags |= ATA_FLAG_NCQ; + + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + + ahci_set_em_messages(hpriv, &pi); + + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at + * both CAP.NP and port_map. + */ + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(dev, ppi, n_ports); + if (!host) + return -ENOMEM; + + host->private_data = hpriv; + + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) + host->flags |= ATA_HOST_PARALLEL_SCAN; + else + dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); + + if (pi.flags & ATA_FLAG_EM) + ahci_reset_em(host); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + ata_port_desc(ap, "mmio %pR", + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); + + /* set enclosure management message type */ + if (ap->flags & ATA_FLAG_EM) + ap->em_message_type = hpriv->em_msg_type; + + /* disabled/not-implemented port */ + if (!(hpriv->port_map & (1 << i))) + ap->ops = &ata_dummy_port_ops; + } + + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + ahci_print_info(host, "platform"); + + return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, + &ahci_platform_sht); +} +EXPORT_SYMBOL_GPL(ahci_platform_init_host); + +static void ahci_host_stop(struct ata_host *host) +{ + struct device *dev = host->dev; + struct ahci_platform_data *pdata = dev_get_platdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + + if (pdata && pdata->exit) + pdata->exit(dev); + + ahci_platform_disable_resources(hpriv); +} + +#ifdef CONFIG_PM_SLEEP +/** + * ahci_platform_suspend_host - Suspend an ahci-platform host + * @dev: device pointer for the host + * + * This function does all the usual steps needed to suspend an + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) + * must be disabled after calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_suspend_host(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 ctl; + + if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { + dev_err(dev, "firmware update required for suspend/resume\n"); + return -EIO; + } + + /* + * AHCI spec rev1.1 section 8.3.3: + * Software must disable interrupts prior to requesting a + * transition of the HBA to D3 state. + */ + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + + return ata_host_suspend(host, PMSG_SUSPEND); +} +EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); + +/** + * ahci_platform_resume_host - Resume an ahci-platform host + * @dev: device pointer for the host + * + * This function does all the usual steps needed to resume an ahci-platform + * host, note any necessary resources (ie clks, phy, etc.) must be + * initialized / enabled before calling this. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_resume_host(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + int rc; + + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + } + + ata_host_resume(host); + + return 0; +} +EXPORT_SYMBOL_GPL(ahci_platform_resume_host); + +/** + * ahci_platform_suspend - Suspend an ahci-platform device + * @dev: the platform device to suspend + * + * This function suspends the host associated with the device, followed by + * disabling all the resources of the device. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_suspend(struct device *dev) +{ + struct ahci_platform_data *pdata = dev_get_platdata(dev); + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + rc = ahci_platform_suspend_host(dev); + if (rc) + return rc; + + if (pdata && pdata->suspend) { + rc = pdata->suspend(dev); + if (rc) + goto resume_host; + } + + ahci_platform_disable_resources(hpriv); + + return 0; + +resume_host: + ahci_platform_resume_host(dev); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_suspend); + +/** + * ahci_platform_resume - Resume an ahci-platform device + * @dev: the platform device to resume + * + * This function enables all the resources of the device followed by + * resuming the host associated with the device. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_resume(struct device *dev) +{ + struct ahci_platform_data *pdata = dev_get_platdata(dev); + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + if (pdata && pdata->resume) { + rc = pdata->resume(dev); + if (rc) + goto disable_resources; + } + + rc = ahci_platform_resume_host(dev); + if (rc) + goto disable_resources; + + /* We resumed so update PM runtime state */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_resume); +#endif + +MODULE_DESCRIPTION("AHCI SATA platform library"); +MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9e69a5308693..97a14fe47de1 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev) dev->gtf_cache = NULL; } +struct ata_acpi_hotplug_context { + struct acpi_hotplug_context hp; + union { + struct ata_port *ap; + struct ata_device *dev; + } data; +}; + +#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data) + /** * ata_dev_acpi_handle - provide the acpi_handle for an ata_device * @dev: the acpi_handle returned will correspond to this device @@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, ata_port_wait_eh(ap); } -static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event) { - struct ata_device *dev = data; - + struct ata_device *dev = ata_hotplug_data(adev->hp).dev; ata_acpi_handle_hotplug(dev->link->ap, dev, event); + return 0; } -static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event) { - struct ata_port *ap = data; - - ata_acpi_handle_hotplug(ap, NULL, event); + ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event); + return 0; } static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, @@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, } } -static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event) { - ata_acpi_uevent(data, NULL, event); + ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event); } -static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) +static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event) { - struct ata_device *dev = data; + struct ata_device *dev = ata_hotplug_data(adev->hp).dev; ata_acpi_uevent(dev->link->ap, dev, event); } -static const struct acpi_dock_ops ata_acpi_dev_dock_ops = { - .handler = ata_acpi_dev_notify_dock, - .uevent = ata_acpi_dev_uevent, -}; - -static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { - .handler = ata_acpi_ap_notify_dock, - .uevent = ata_acpi_ap_uevent, -}; - /* bind acpi handle to pata port */ void ata_acpi_bind_port(struct ata_port *ap) { struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); + struct acpi_device *adev; + struct ata_acpi_hotplug_context *context; if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) return; @@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap) if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; - /* we might be on a docking station */ - register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev), - &ata_acpi_ap_dock_ops, ap, NULL, NULL); + adev = ACPI_COMPANION(&ap->tdev); + if (!adev || adev->hp) + return; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return; + + context->data.ap = ap; + acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock, + ata_acpi_ap_uevent); } void ata_acpi_bind_dev(struct ata_device *dev) @@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev) struct ata_port *ap = dev->link->ap; struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); - struct acpi_device *parent; + struct acpi_device *parent, *adev; + struct ata_acpi_hotplug_context *context; u64 adr; /* @@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev) } acpi_preset_companion(&dev->tdev, parent, adr); + adev = ACPI_COMPANION(&dev->tdev); + if (!adev || adev->hp) + return; + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return; - register_hotplug_dock_device(ata_dev_acpi_handle(dev), - &ata_acpi_dev_dock_ops, dev, NULL, NULL); + context->data.dev = dev; + acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock, + ata_acpi_dev_uevent); } /** @@ -835,6 +853,7 @@ void ata_acpi_on_resume(struct ata_port *ap) ata_for_each_dev(dev, &ap->link, ALL) { ata_acpi_clear_gtf(dev); if (ata_dev_enabled(dev) && + ata_dev_acpi_handle(dev) && ata_dev_get_GTF(dev, NULL) >= 0) dev->flags |= ATA_DFLAG_ACPI_PENDING; } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1a3dbd1b196e..c19734d96d7e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1524,7 +1524,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command - * @dma_dir: Data tranfer direction of the command + * @dma_dir: Data transfer direction of the command * @sgl: sg list for the data buffer of the command * @n_elem: Number of sg entries * @timeout: Timeout in msecs (0 for default) @@ -1712,7 +1712,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command - * @dma_dir: Data tranfer direction of the command + * @dma_dir: Data transfer direction of the command * @buf: Data buffer of the command * @buflen: Length of data buffer * @timeout: Timeout in msecs (0 for default) @@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA }, + { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ @@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* devices that don't properly handle queued TRIM commands */ { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, /* * Some WD SATA-I drives spin up and down erratically when the link @@ -5351,22 +5352,17 @@ bool ata_link_offline(struct ata_link *link) } #ifdef CONFIG_PM -static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, - unsigned int action, unsigned int ehi_flags, - int *async) +static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, + unsigned int action, unsigned int ehi_flags, + bool async) { struct ata_link *link; unsigned long flags; - int rc = 0; /* Previous resume operation might still be in * progress. Wait for PM_PENDING to clear. */ if (ap->pflags & ATA_PFLAG_PM_PENDING) { - if (async) { - *async = -EAGAIN; - return 0; - } ata_port_wait_eh(ap); WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); } @@ -5375,11 +5371,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, spin_lock_irqsave(ap->lock, flags); ap->pm_mesg = mesg; - if (async) - ap->pm_result = async; - else - ap->pm_result = &rc; - ap->pflags |= ATA_PFLAG_PM_PENDING; ata_for_each_link(link, ap, HOST_FIRST) { link->eh_info.action |= action; @@ -5390,87 +5381,81 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, spin_unlock_irqrestore(ap->lock, flags); - /* wait and check result */ if (!async) { ata_port_wait_eh(ap); WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); } - - return rc; } -static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async) +/* + * On some hardware, device fails to respond after spun down for suspend. As + * the device won't be used before being resumed, we don't need to touch the + * device. Ask EH to skip the usual stuff and proceed directly to suspend. + * + * http://thread.gmane.org/gmane.linux.ide/46764 + */ +static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET + | ATA_EHI_NO_AUTOPSY + | ATA_EHI_NO_RECOVERY; + +static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg) { - /* - * On some hardware, device fails to respond after spun down - * for suspend. As the device won't be used before being - * resumed, we don't need to touch the device. Ask EH to skip - * the usual stuff and proceed directly to suspend. - * - * http://thread.gmane.org/gmane.linux.ide/46764 - */ - unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY | - ATA_EHI_NO_RECOVERY; - return ata_port_request_pm(ap, mesg, 0, ehi_flags, async); + ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false); } -static int ata_port_suspend_common(struct device *dev, pm_message_t mesg) +static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg) { - struct ata_port *ap = to_ata_port(dev); - - return __ata_port_suspend_common(ap, mesg, NULL); + ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true); } -static int ata_port_suspend(struct device *dev) +static int ata_port_pm_suspend(struct device *dev) { + struct ata_port *ap = to_ata_port(dev); + if (pm_runtime_suspended(dev)) return 0; - return ata_port_suspend_common(dev, PMSG_SUSPEND); + ata_port_suspend(ap, PMSG_SUSPEND); + return 0; } -static int ata_port_do_freeze(struct device *dev) +static int ata_port_pm_freeze(struct device *dev) { + struct ata_port *ap = to_ata_port(dev); + if (pm_runtime_suspended(dev)) return 0; - return ata_port_suspend_common(dev, PMSG_FREEZE); + ata_port_suspend(ap, PMSG_FREEZE); + return 0; } -static int ata_port_poweroff(struct device *dev) +static int ata_port_pm_poweroff(struct device *dev) { - return ata_port_suspend_common(dev, PMSG_HIBERNATE); + ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE); + return 0; } -static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg, - int *async) -{ - int rc; +static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY + | ATA_EHI_QUIET; - rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET, - ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async); - return rc; +static void ata_port_resume(struct ata_port *ap, pm_message_t mesg) +{ + ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false); } -static int ata_port_resume_common(struct device *dev, pm_message_t mesg) +static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg) { - struct ata_port *ap = to_ata_port(dev); - - return __ata_port_resume_common(ap, mesg, NULL); + ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true); } -static int ata_port_resume(struct device *dev) +static int ata_port_pm_resume(struct device *dev) { - int rc; - - rc = ata_port_resume_common(dev, PMSG_RESUME); - if (!rc) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - - return rc; + ata_port_resume_async(to_ata_port(dev), PMSG_RESUME); + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; } /* @@ -5499,21 +5484,23 @@ static int ata_port_runtime_idle(struct device *dev) static int ata_port_runtime_suspend(struct device *dev) { - return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND); + ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND); + return 0; } static int ata_port_runtime_resume(struct device *dev) { - return ata_port_resume_common(dev, PMSG_AUTO_RESUME); + ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME); + return 0; } static const struct dev_pm_ops ata_port_pm_ops = { - .suspend = ata_port_suspend, - .resume = ata_port_resume, - .freeze = ata_port_do_freeze, - .thaw = ata_port_resume, - .poweroff = ata_port_poweroff, - .restore = ata_port_resume, + .suspend = ata_port_pm_suspend, + .resume = ata_port_pm_resume, + .freeze = ata_port_pm_freeze, + .thaw = ata_port_pm_resume, + .poweroff = ata_port_pm_poweroff, + .restore = ata_port_pm_resume, .runtime_suspend = ata_port_runtime_suspend, .runtime_resume = ata_port_runtime_resume, @@ -5525,18 +5512,17 @@ static const struct dev_pm_ops ata_port_pm_ops = { * level. sas suspend/resume is async to allow parallel port recovery * since sas has multiple ata_port instances per Scsi_Host. */ -int ata_sas_port_async_suspend(struct ata_port *ap, int *async) +void ata_sas_port_suspend(struct ata_port *ap) { - return __ata_port_suspend_common(ap, PMSG_SUSPEND, async); + ata_port_suspend_async(ap, PMSG_SUSPEND); } -EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend); +EXPORT_SYMBOL_GPL(ata_sas_port_suspend); -int ata_sas_port_async_resume(struct ata_port *ap, int *async) +void ata_sas_port_resume(struct ata_port *ap) { - return __ata_port_resume_common(ap, PMSG_RESUME, async); + ata_port_resume_async(ap, PMSG_RESUME); } -EXPORT_SYMBOL_GPL(ata_sas_port_async_resume); - +EXPORT_SYMBOL_GPL(ata_sas_port_resume); /** * ata_host_suspend - suspend host diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 6d8757008318..6760fc4e85b8 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -95,12 +95,13 @@ enum { * represents timeout for that try. The first try can be soft or * hardreset. All others are hardreset if available. In most cases * the first reset w/ 10sec timeout should succeed. Following entries - * are mostly for error handling, hotplug and retarded devices. + * are mostly for error handling, hotplug and those outlier devices that + * take an exceptionally long time to recover from reset. */ static const unsigned long ata_eh_reset_timeouts[] = { 10000, /* most drives spin up by 10sec */ 10000, /* > 99% working drives spin up before 20sec */ - 35000, /* give > 30 secs of idleness for retarded devices */ + 35000, /* give > 30 secs of idleness for outlier devices */ 5000, /* and sweet one last chance */ ULONG_MAX, /* > 1 min has elapsed, give up */ }; @@ -4069,7 +4070,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) ata_acpi_set_state(ap, ap->pm_mesg); out: - /* report result */ + /* update the flags */ spin_lock_irqsave(ap->lock, flags); ap->pflags &= ~ATA_PFLAG_PM_PENDING; @@ -4078,11 +4079,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) else if (ap->pflags & ATA_PFLAG_FROZEN) ata_port_schedule_eh(ap); - if (ap->pm_result) { - *ap->pm_result = rc; - ap->pm_result = NULL; - } - spin_unlock_irqrestore(ap->lock, flags); return; @@ -4134,13 +4130,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) /* tell ACPI that we're resuming */ ata_acpi_on_resume(ap); - /* report result */ + /* update the flags */ spin_lock_irqsave(ap->lock, flags); ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); - if (ap->pm_result) { - *ap->pm_result = rc; - ap->pm_result = NULL; - } spin_unlock_irqrestore(ap->lock, flags); } #endif /* CONFIG_PM */ diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 20fd337a5731..7ccc084bf1df 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; - } else if (vendor == 0x197b && devid == 0x2352) { - /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) { + /* + * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350? + * 0x0325: jmicron JMB394. + */ ata_for_each_link(link, ap, EDGE) { /* SRST breaks detection and disks get misclassified * LPM disabled to avoid potential problems diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 88949c6d55dd..f3a65a3140d3 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -85,21 +85,6 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) return ODD_MECH_TYPE_UNSUPPORTED; } -static bool odd_can_poweroff(struct ata_device *ata_dev) -{ - acpi_handle handle; - struct acpi_device *acpi_dev; - - handle = ata_dev_acpi_handle(ata_dev); - if (!handle) - return false; - - if (acpi_bus_get_device(handle, &acpi_dev)) - return false; - - return acpi_device_can_poweroff(acpi_dev); -} - /* Test if ODD is zero power ready by sense code */ static bool zpready(struct ata_device *dev) { @@ -267,13 +252,11 @@ static void ata_acpi_remove_pm_notifier(struct ata_device *dev) void zpodd_init(struct ata_device *dev) { + struct acpi_device *adev = ACPI_COMPANION(&dev->tdev); enum odd_mech_type mech_type; struct zpodd *zpodd; - if (dev->zpodd) - return; - - if (!odd_can_poweroff(dev)) + if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev)) return; mech_type = zpodd_get_mech_type(dev); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 62c9ac80c6e9..5108b8744dce 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -7,7 +7,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index d23e2b3ca0b6..1206fa6b62ca 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 73492dd4a4bc..6fac524c2f50 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -356,7 +356,7 @@ static void cf_exit(struct arasan_cf_dev *acdev) static void dma_callback(void *dev) { - struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev; + struct arasan_cf_dev *acdev = dev; complete(&acdev->dma_completion); } diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 1581dee2967a..3aa4e655e3c6 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index d63ee8f41a4f..e9c87274a781 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -18,7 +18,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/gfp.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 24e51056ac26..30fa4ca4cef6 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c index 2ca5026f2c15..7e73a0f1e323 100644 --- a/drivers/ata/pata_atp867x.c +++ b/drivers/ata/pata_atp867x.c @@ -29,7 +29,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 8fb69e5ca1b7..57f1be64dbf2 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/gfp.h> diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 1275a8d4dedc..6bca3505b9e9 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index f10baabbf5db..bcde4b786807 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -34,7 +34,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index f07f2296acdc..8afe854a5a50 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 997e16a3a63f..2c0986fa4bb2 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 0448860a2077..32ddcae5a360 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -33,7 +33,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/libata.h> diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 810bc9964dde..3435bd6a5cc9 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 3c12fd7acd41..f440892225f4 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index 980b88e109fc..cad9d45749c4 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -34,7 +34,6 @@ #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <scsi/scsi_host.h> #include <linux/ata.h> diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 35b521348d31..8e76f79689d3 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index a9d74eff5fc4..3ba843f5cdc0 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 4be0398c153d..b93c0f0729e7 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 85cf2861e0b7..255c5aaff3a8 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 26386f0b89a8..e0872db913d6 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -15,7 +15,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <scsi/scsi_host.h> #include <linux/ata.h> @@ -100,13 +99,9 @@ static int pata_imx_probe(struct platform_device *pdev) struct resource *io_res; int ret; - io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (io_res == NULL) - return -EINVAL; - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -EINVAL; + if (irq < 0) + return irq; priv = devm_kzalloc(&pdev->dev, sizeof(struct pata_imx_priv), GFP_KERNEL); @@ -119,7 +114,9 @@ static int pata_imx_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; host = ata_host_alloc(&pdev->dev, 1); if (!host) { @@ -134,11 +131,10 @@ static int pata_imx_probe(struct platform_device *pdev) ap->pio_mask = ATA_PIO0; ap->flags |= ATA_FLAG_SLAVE_POSS; - priv->host_regs = devm_ioremap(&pdev->dev, io_res->start, - resource_size(io_res)); - if (!priv->host_regs) { - dev_err(&pdev->dev, "failed to map IO/CTL base\n"); - ret = -EBUSY; + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res); + if (IS_ERR(priv->host_regs)) { + ret = PTR_ERR(priv->host_regs); goto err; } @@ -212,7 +208,9 @@ static int pata_imx_resume(struct device *dev) struct ata_host *host = dev_get_drvdata(dev); struct pata_imx_priv *priv = host->private_data; - clk_prepare_enable(priv->clk); + int ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL); diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 2a8dd9527ecc..81369d187a5c 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -10,7 +10,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 581e04d80367..dc3d7877f29d 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -72,7 +72,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/slab.h> diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 76e739b031b6..b1cfa0258fd3 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -10,7 +10,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index be816428b430..bce2a8ca4678 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -916,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe) local_irq_restore(flags); return BIOS; } - local_irq_restore(flags); } if (ht6560a & mask) diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index a4f5e781c8c2..6bad3df3a13c 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 1f5f28bb0bb8..f39a5379e816 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -28,7 +28,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index ad1a0febd620..e3b97093ef9a 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -7,7 +7,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 9513e071040d..56201a69af12 100644 --- a/drivers/ata/pata_ninja32.c +++ b/drivers/ata/pata_ninja32.c @@ -37,7 +37,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 0c424dae56e7..6154c3ee11a5 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 16dc3a63a23d..d44df7ccfe43 100644 --- a/drivers/ata/pata_ns87415.c +++ b/drivers/ata/pata_ns87415.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index d77b2e1054ef..319b64491b7b 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 4ea70cd22aee..fb042e0519d0 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 78ede3fd1875..bb71ea214b99 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 40254f4df584..bcc4b968c049 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/slab.h> diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 9d874c85d64d..1151f23177bb 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index c34fc50070a6..defa050e1784 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c index 2beb6b5045f8..0b46be117051 100644 --- a/drivers/ata/pata_piccolo.c +++ b/drivers/ata/pata_piccolo.c @@ -18,7 +18,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 02794885de10..a5579b55e332 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -13,7 +13,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <scsi/scsi_host.h> #include <linux/ata.h> diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index a6f05acad61e..73259bfda1e3 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/ata.h> #include <linux/libata.h> diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index f582ba180a7d..be3f10240dca 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c index 79a970f05a2e..521b2137ea3e 100644 --- a/drivers/ata/pata_rdc.c +++ b/drivers/ata/pata_rdc.c @@ -24,7 +24,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 040b093617a4..caedc90855b2 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index ce2f828c17b3..96a232fffae6 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index f35f15f4d83e..f1f5b5ae3382 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c index d3830c45a369..5a1cde0ea360 100644 --- a/drivers/ata/pata_sch.c +++ b/drivers/ata/pata_sch.c @@ -27,7 +27,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 96c6a79ef606..e27f31fe1b67 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -34,7 +34,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c4b0b073ba8e..73fe362d9716 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -25,7 +25,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 1e8363640bf5..78d913aa93c8 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 6816911ac422..900f0e4a1faf 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 94473da68c02..7bc78e264f9e 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -36,7 +36,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index c3ab9a6c3965..f6c9632bdff6 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -55,7 +55,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/gfp.h> diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 8ea6e6afd041..f10631beffa8 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -36,7 +36,6 @@ #include <linux/module.h> #include <linux/gfp.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 523524b68022..0bb2cabd2197 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -29,7 +29,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/device.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -462,8 +461,7 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) int chan; u32 tfr_reg, err_reg; unsigned long flags; - struct sata_dwc_device *hsdev = - (struct sata_dwc_device *)hsdev_instance; + struct sata_dwc_device *hsdev = hsdev_instance; struct ata_host *host = (struct ata_host *)hsdev->host; struct ata_port *ap; struct sata_dwc_device_port *hsdevp; diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 870b11eadc6d..65965cf5af06 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/types.h> #include <linux/err.h> #include <linux/io.h> @@ -142,7 +141,7 @@ static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state, ssize_t size) { struct ahci_host_priv *hpriv = ap->host->private_data; - struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data; + struct ecx_plat_data *pdata = hpriv->plat_data; struct ahci_port_priv *pp = ap->private_data; unsigned long flags; int pmp, i; @@ -403,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, static const unsigned long timing[] = { 5, 100, 500}; struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; bool online; @@ -431,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, break; } while (!online && retry--); - ahci_start_engine(ap); + hpriv->start_engine(ap); if (online) *class = ahci_dev_classify(ap); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 52b8181ddafd..05c8a44adf8e 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev) if (!hpriv->port_phys) return -ENOMEM; host->private_data = hpriv; - hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; host->iomap = NULL; @@ -4132,13 +4131,18 @@ static int mv_platform_probe(struct platform_device *pdev) rc = PTR_ERR(hpriv->port_phys[port]); hpriv->port_phys[port] = NULL; if (rc != -EPROBE_DEFER) - dev_warn(&pdev->dev, "error getting phy %d", - rc); + dev_warn(&pdev->dev, "error getting phy %d", rc); + + /* Cleanup only the initialized ports */ + hpriv->n_ports = port; goto err; } else phy_power_on(hpriv->port_phys[port]); } + /* All the ports have been initialized */ + hpriv->n_ports = n_ports; + /* * (Re-)program MBUS remapping windows if we are asked to. */ @@ -4176,7 +4180,7 @@ err: clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } - for (port = 0; port < n_ports; port++) { + for (port = 0; port < hpriv->n_ports; port++) { if (!IS_ERR(hpriv->port_clks[port])) { clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index d74def823d3e..ba5f27120332 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -40,7 +40,6 @@ #include <linux/module.h> #include <linux/gfp.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 97f4acb54ad6..3638887476f6 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -35,7 +35,6 @@ #include <linux/module.h> #include <linux/gfp.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 3b0dd57984e1..9a6bd4cd29a0 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -31,7 +31,6 @@ #include <linux/module.h> #include <linux/gfp.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index d67fc351343c..3062f8605b29 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -37,7 +37,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -157,6 +156,7 @@ static const struct sil_drivelist { { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, + { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE }, { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, { } }; diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 1ad2f62d34b9..b513428171b3 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -33,7 +33,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index dc4f70179e7d..c630fa812624 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -39,7 +39,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 9947010afc0f..39b5de60a1f9 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -82,7 +82,6 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -1021,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, idx++; dist = ((long) (window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), - dist); + memcpy_fromio(psource, dimm_mmio + offset / 4, dist); psource += dist; size -= dist; @@ -1031,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), - window_size / 4); + memcpy_fromio(psource, dimm_mmio, window_size / 4); psource += window_size; size -= window_size; idx++; @@ -1043,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource, readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), - size / 4); + memcpy_fromio(psource, dimm_mmio, size / 4); } } #endif diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 6d6489118873..08f98c3ed5c8 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/gfp.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 87f056e54a9d..f72e84228c5c 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -36,7 +36,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 44f304b3de63..29e847aac34b 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -37,7 +37,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> |