diff options
Diffstat (limited to 'drivers/ata')
104 files changed, 6293 insertions, 1037 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4e737728aee..2664da32d9d 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,56 @@ 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 && (ARCH_MXC || COMPILE_TEST)  	help  	  This option enables support for the Freescale i.MX SoC's  	  onboard AHCI SATA.  	  If unsure, say N. +config AHCI_MVEBU +	tristate "Marvell EBU AHCI SATA support" +	depends on ARCH_MVEBU +	help +	  This option enables support for the Marvebu EBU 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 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 @@ -237,8 +278,18 @@ config SATA_DWC_VDEBUG  	help  	  This option enables the taskfile dumping and NCQ debugging. +config SATA_DWC_PMP +	tristate "DesignWare Cores SATA with PMP support" +	depends on 460EX +	help +	  This option enables support for the on-chip SATA controller of the +	  AppliedMicro processor 460EX with PMP support. + +	  If unsure, say N. +  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 +298,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 +326,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 +406,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 +458,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 +467,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 +476,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 +485,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 +721,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. @@ -777,7 +833,7 @@ config PATA_AT32  config PATA_AT91  	tristate "PATA support for AT91SAM9260" -	depends on ARM && ARCH_AT91 +	depends on ARM && SOC_AT91SAM9  	help  	  This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 46518c62246..7e7a77de757 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -4,13 +4,19 @@ 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_DWC_PMP)	+= sata_dwc_pmp.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_MVEBU)	+= ahci_mvebu.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 fd665d919df..0cd7c7a39e5 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> @@ -78,7 +77,7 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);  static int acard_ahci_port_start(struct ata_port *ap);  static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);  static int acard_ahci_pci_device_resume(struct pci_dev *pdev);  #endif @@ -119,13 +118,13 @@ static struct pci_driver acard_ahci_pci_driver = {  	.id_table		= acard_ahci_pci_tbl,  	.probe			= acard_ahci_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= acard_ahci_pci_device_suspend,  	.resume			= acard_ahci_pci_device_resume,  #endif  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)  {  	struct ata_host *host = pci_get_drvdata(pdev); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9d715ae5ff6..4cd52a4541a 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, @@ -83,6 +83,8 @@ enum board_ids {  static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);  static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,  				 unsigned long deadline); +static void ahci_mcp89_apple_enable(struct pci_dev *pdev); +static bool is_mcp89_apple(struct pci_dev *pdev);  static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,  				unsigned long deadline);  #ifdef CONFIG_PM @@ -119,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, @@ -292,6 +301,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {  	{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */  	{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */  	{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */ +	{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */ +	{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */ +	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */ +	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */  	/* JMicron 360/1/3/5/6, match class to avoid IDE function */  	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -423,17 +436,27 @@ static const struct pci_device_id ahci_pci_tbl[] = {  	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */  	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),  	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178, +			 PCI_VENDOR_ID_MARVELL_EXT, 0x9170), +	  .driver_data = board_ahci_yes_fbs },			/* 88se9170 */  	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),  	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */  	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),  	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */  	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),  	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 on some Gigabyte */ +	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0), +	  .driver_data = board_ahci_yes_fbs },  	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),  	  .driver_data = board_ahci_yes_fbs }, +	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), +	  .driver_data = board_ahci_yes_fbs }, +	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), +	  .driver_data = board_ahci_yes_fbs },  	/* Promise */  	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */ +	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */  	/* Asmedia */  	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },	/* ASM1060 */ @@ -441,6 +464,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 }, @@ -553,6 +582,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; @@ -563,7 +593,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); @@ -578,6 +608,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; @@ -593,7 +624,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 @@ -655,6 +686,10 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)  	if (rc)  		return rc; +	/* Apple BIOS helpfully mangles the registers on resume */ +	if (is_mcp89_apple(pdev)) +		ahci_mcp89_apple_enable(pdev); +  	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {  		rc = ahci_pci_reset_controller(host);  		if (rc) @@ -771,6 +806,48 @@ static void ahci_p5wdh_workaround(struct ata_host *host)  	}  } +/* + * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when + * booting in BIOS compatibility mode.  We restore the registers but not ID. + */ +static void ahci_mcp89_apple_enable(struct pci_dev *pdev) +{ +	u32 val; + +	printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n"); + +	pci_read_config_dword(pdev, 0xf8, &val); +	val |= 1 << 0x1b; +	/* the following changes the device ID, but appears not to affect function */ +	/* val = (val & ~0xf0000000) | 0x80000000; */ +	pci_write_config_dword(pdev, 0xf8, val); + +	pci_read_config_dword(pdev, 0x54c, &val); +	val |= 1 << 0xc; +	pci_write_config_dword(pdev, 0x54c, val); + +	pci_read_config_dword(pdev, 0x4a4, &val); +	val &= 0xff; +	val |= 0x01060100; +	pci_write_config_dword(pdev, 0x4a4, val); + +	pci_read_config_dword(pdev, 0x54c, &val); +	val &= ~(1 << 0xc); +	pci_write_config_dword(pdev, 0x54c, val); + +	pci_read_config_dword(pdev, 0xf8, &val); +	val &= ~(1 << 0x1b); +	pci_write_config_dword(pdev, 0xf8, val); +} + +static bool is_mcp89_apple(struct pci_dev *pdev) +{ +	return pdev->vendor == PCI_VENDOR_ID_NVIDIA && +		pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA && +		pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && +		pdev->subsystem_device == 0xcb89; +} +  /* only some SB600 ahci controllers can do 64bit DMA */  static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)  { @@ -1043,6 +1120,17 @@ static bool ahci_broken_online(struct pci_dev *pdev)  	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);  } +static bool ahci_broken_devslp(struct pci_dev *pdev) +{ +	/* device with broken DEVSLP but still showing SDS capability */ +	static const struct pci_device_id ids[] = { +		{ PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */ +		{} +	}; + +	return pci_match_id(ids, pdev); +} +  #ifdef CONFIG_ATA_ACPI  static void ahci_gtf_filter_workaround(struct ata_host *host)  { @@ -1091,26 +1179,47 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)  {}  #endif -int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) +static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, +				struct ahci_host_priv *hpriv)  { -	int rc; -	unsigned int maxvec; +	int rc, nvec; -	if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) { -		rc = pci_enable_msi_block_auto(pdev, &maxvec); -		if (rc > 0) { -			if ((rc == maxvec) || (rc == 1)) -				return rc; -			/* -			 * Assume that advantage of multipe MSIs is negated, -			 * so fallback to single MSI mode to save resources -			 */ -			pci_disable_msi(pdev); -			if (!pci_enable_msi(pdev)) -				return 1; -		} +	if (hpriv->flags & AHCI_HFLAG_NO_MSI) +		goto intx; + +	nvec = pci_msi_vec_count(pdev); +	if (nvec < 0) +		goto intx; + +	/* +	 * If number of MSIs is less than number of ports then Sharing Last +	 * Message mode could be enforced. In this case assume that advantage +	 * of multipe MSIs is negated and use single MSI mode instead. +	 */ +	if (nvec < n_ports) +		goto single_msi; + +	rc = pci_enable_msi_exact(pdev, nvec); +	if (rc == -ENOSPC) +		goto single_msi; +	else if (rc < 0) +		goto intx; + +	/* fallback to single MSI mode if the controller enforced MRSM mode */ +	if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { +		pci_disable_msi(pdev); +		printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n"); +		goto single_msi;  	} +	return nvec; + +single_msi: +	if (pci_enable_msi(pdev)) +		goto intx; +	return 1; + +intx:  	pci_intx(pdev, 1);  	return 0;  } @@ -1146,18 +1255,18 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)  		return rc;  	for (i = 0; i < host->n_ports; i++) { -		const char* desc;  		struct ahci_port_priv *pp = host->ports[i]->private_data; -		/* pp is NULL for dummy ports */ -		if (pp) -			desc = pp->irq_desc; -		else -			desc = dev_driver_string(host->dev); +		/* Do not receive interrupts sent by dummy ports */ +		if (!pp) { +			disable_irq(irq + i); +			continue; +		} -		rc = devm_request_threaded_irq(host->dev, -			irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED, -			desc, host->ports[i]); +		rc = devm_request_threaded_irq(host->dev, irq + i, +					       ahci_hw_interrupt, +					       ahci_thread_fn, IRQF_SHARED, +					       pp->irq_desc, host->ports[i]);  		if (rc)  			goto out_free_irqs;  	} @@ -1203,15 +1312,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)  		return -ENODEV; -	/* -	 * For some reason, MCP89 on MacBook 7,1 doesn't work with -	 * ahci, use ata_generic instead. -	 */ -	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && -	    pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA && -	    pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && -	    pdev->subsystem_device == 0xcb89) -		return -ENODEV; +	/* Apple BIOS on MCP89 prevents us using AHCI */ +	if (is_mcp89_apple(pdev)) +		ahci_mcp89_apple_enable(pdev);  	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.  	 * At the moment, we can only use the AHCI mode. Let the users know @@ -1232,15 +1335,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (rc)  		return rc; -	/* AHCI controllers often implement SFF compatible interface. -	 * Grab all PCI BARs just in case. -	 */ -	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME); -	if (rc == -EBUSY) -		pcim_pin_device(pdev); -	if (rc) -		return rc; -  	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&  	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {  		u8 map; @@ -1257,6 +1351,15 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  		}  	} +	/* AHCI controllers often implement SFF compatible interface. +	 * Grab all PCI BARs just in case. +	 */ +	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME); +	if (rc == -EBUSY) +		pcim_pin_device(pdev); +	if (rc) +		return rc; +  	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);  	if (!hpriv)  		return -ENOMEM; @@ -1277,9 +1380,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; -	n_msis = ahci_init_interrupts(pdev, hpriv); -	if (n_msis > 1) -		hpriv->flags |= AHCI_HFLAG_MULTI_MSI; +	/* must set flag prior to save config in order to take effect */ +	if (ahci_broken_devslp(pdev)) +		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;  	/* save initial config */  	ahci_pci_save_initial_config(pdev, hpriv); @@ -1335,6 +1438,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	 */  	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); +	n_msis = ahci_init_interrupts(pdev, n_ports, hpriv); +	if (n_msis > 1) +		hpriv->flags |= AHCI_HFLAG_MULTI_MSI; +  	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);  	if (!host)  		return -ENOMEM; @@ -1343,7 +1450,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)  		host->flags |= ATA_HOST_PARALLEL_SCAN;  	else -		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n"); +		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");  	if (pi.flags & ATA_FLAG_EM)  		ahci_reset_em(host); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 11456371f29..5513296e5e2 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, @@ -91,6 +94,7 @@ enum {  	/* HOST_CTL bits */  	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */  	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */ +	HOST_MRSM		= (1 << 2),  /* MSI Revert to Single Message */  	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */  	/* HOST_CAP bits */ @@ -232,6 +236,8 @@ enum {  						        port start (wait until  						        error-handling stage) */  	AHCI_HFLAG_MULTI_MSI		= (1 << 16), /* multiple PCI MSIs */ +	AHCI_HFLAG_NO_DEVSLP		= (1 << 17), /* no device sleep */ +	AHCI_HFLAG_NO_FBS		= (1 << 18), /* no FBS */  	/* ap->flags bits */ @@ -321,8 +327,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; @@ -339,6 +354,7 @@ extern struct device_attribute *ahci_sdev_attrs[];  	.sdev_attrs		= ahci_sdev_attrs  extern struct ata_port_operations ahci_ops; +extern struct ata_port_operations ahci_platform_ops;  extern struct ata_port_operations ahci_pmp_retry_srst_ops;  unsigned int ahci_dev_classify(struct ata_port *ap); @@ -355,7 +371,9 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  		      int pmp, unsigned long deadline,  		      int (*check_ready)(struct ata_link *link)); +unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);  int ahci_stop_engine(struct ata_port *ap); +void ahci_start_fis_rx(struct ata_port *ap);  void ahci_start_engine(struct ata_port *ap);  int ahci_check_ready(struct ata_link *link);  int ahci_kick_engine(struct ata_port *ap); @@ -368,6 +386,7 @@ irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);  irqreturn_t ahci_thread_fn(int irq, void *dev_instance);  void ahci_print_info(struct ata_host *host, const char *scc_s);  int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); +void ahci_error_handler(struct ata_port *ap);  static inline void __iomem *__ahci_port_base(struct ata_host *host,  					     unsigned int port_no) diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c new file mode 100644 index 00000000000..2b77d53bccf --- /dev/null +++ b/drivers/ata/ahci_da850.c @@ -0,0 +1,115 @@ +/* + * 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, 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 58debb0acc3..cac4360f272 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -1,6 +1,6 @@  /* + * copyright (c) 2013 Freescale Semiconductor, Inc.   * Freescale IMX AHCI SATA platform driver - * Copyright 2013 Freescale Semiconductor, Inc.   *   * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov   * @@ -25,105 +25,346 @@  #include <linux/of_device.h>  #include <linux/mfd/syscon.h>  #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/libata.h>  #include "ahci.h"  enum { -	HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ +	/* Timer 1-ms Register */ +	IMX_TIMER1MS				= 0x00e0, +	/* Port0 PHY Control Register */ +	IMX_P0PHYCR				= 0x0178, +	IMX_P0PHYCR_TEST_PDDQ			= 1 << 20, +	IMX_P0PHYCR_CR_READ			= 1 << 19, +	IMX_P0PHYCR_CR_WRITE			= 1 << 18, +	IMX_P0PHYCR_CR_CAP_DATA			= 1 << 17, +	IMX_P0PHYCR_CR_CAP_ADDR			= 1 << 16, +	/* Port0 PHY Status Register */ +	IMX_P0PHYSR				= 0x017c, +	IMX_P0PHYSR_CR_ACK			= 1 << 18, +	IMX_P0PHYSR_CR_DATA_OUT			= 0xffff << 0, +	/* Lane0 Output Status Register */ +	IMX_LANE0_OUT_STAT			= 0x2003, +	IMX_LANE0_OUT_STAT_RX_PLL_STATE		= 1 << 1, +	/* Clock Reset Register */ +	IMX_CLOCK_RESET				= 0x7f3f, +	IMX_CLOCK_RESET_RESET			= 1 << 0, +}; + +enum ahci_imx_type { +	AHCI_IMX53, +	AHCI_IMX6Q,  };  struct imx_ahci_priv {  	struct platform_device *ahci_pdev; +	enum ahci_imx_type type; +	struct clk *sata_clk;  	struct clk *sata_ref_clk;  	struct clk *ahb_clk;  	struct regmap *gpr; +	bool no_device; +	bool first_time;  }; -static int imx6q_sata_init(struct device *dev, void __iomem *mmio) +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 void ahci_imx_host_stop(struct ata_host *host); + +static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert)  { -	int ret = 0; -	unsigned int reg_val; -	struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); +	int timeout = 10; +	u32 crval; +	u32 srval; + +	/* Assert or deassert the bit */ +	crval = readl(mmio + IMX_P0PHYCR); +	if (assert) +		crval |= bit; +	else +		crval &= ~bit; +	writel(crval, mmio + IMX_P0PHYCR); + +	/* Wait for the cr_ack signal */ +	do { +		srval = readl(mmio + IMX_P0PHYSR); +		if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) +			break; +		usleep_range(100, 200); +	} while (--timeout); + +	return timeout ? 0 : -ETIMEDOUT; +} -	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); -	} +static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) +{ +	u32 crval = addr; +	int ret; -	ret = clk_prepare_enable(imxpriv->sata_ref_clk); -	if (ret < 0) { -		dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); +	/* Supply the address on cr_data_in */ +	writel(crval, mmio + IMX_P0PHYCR); + +	/* Assert the cr_cap_addr signal */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); +	if (ret) +		return ret; + +	/* Deassert cr_cap_addr */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); +	if (ret) +		return ret; + +	return 0; +} + +static int imx_phy_reg_write(u16 val, void __iomem *mmio) +{ +	u32 crval = val; +	int ret; + +	/* Supply the data on cr_data_in */ +	writel(crval, mmio + IMX_P0PHYCR); + +	/* Assert the cr_cap_data signal */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); +	if (ret)  		return ret; + +	/* Deassert cr_cap_data */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); +	if (ret) +		return ret; + +	if (val & IMX_CLOCK_RESET_RESET) { +		/* +		 * In case we're resetting the phy, it's unable to acknowledge, +		 * so we return immediately here. +		 */ +		crval |= IMX_P0PHYCR_CR_WRITE; +		writel(crval, mmio + IMX_P0PHYCR); +		goto out;  	} -	/* -	 * set PHY Paremeters, two steps to configure the GPR13, -	 * one write for rest of parameters, mask of first write -	 * is 0x07fffffd, and the other one write for setting -	 * the mpll_clk_en. -	 */ -	regmap_update_bits(imxpriv->gpr, 0x34, 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_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, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN, -			IMX6Q_GPR13_SATA_MPLL_CLK_EN); -	usleep_range(100, 200); +	/* Assert the cr_write signal */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); +	if (ret) +		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); +	/* Deassert cr_write */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); +	if (ret) +		return ret; + +out: +	return 0; +} + +static int imx_phy_reg_read(u16 *val, void __iomem *mmio) +{ +	int ret; + +	/* Assert the cr_read signal */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); +	if (ret) +		return ret; + +	/* Capture the data from cr_data_out[] */ +	*val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; + +	/* Deassert cr_read */ +	ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); +	if (ret) +		return ret; + +	return 0; +} + +static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) +{ +	void __iomem *mmio = hpriv->mmio; +	int timeout = 10; +	u16 val; +	int ret; + +	/* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ +	ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); +	if (ret) +		return ret; +	ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); +	if (ret) +		return ret; + +	/* Wait for PHY RX_PLL to be stable */ +	do { +		usleep_range(100, 200); +		ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); +		if (ret) +			return ret; +		ret = imx_phy_reg_read(&val, mmio); +		if (ret) +			return ret; +		if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) +			break; +	} while (--timeout); + +	return timeout ? 0 : -ETIMEDOUT; +} + +static int imx_sata_enable(struct ahci_host_priv *hpriv) +{ +	struct imx_ahci_priv *imxpriv = hpriv->plat_data; +	struct device *dev = &imxpriv->ahci_pdev->dev; +	int ret; + +	if (imxpriv->no_device) +		return 0; + +	if (hpriv->target_pwr) { +		ret = regulator_enable(hpriv->target_pwr); +		if (ret) +			return ret;  	} -	reg_val = readl(mmio + HOST_PORTS_IMPL); -	if (!(reg_val & 0x1)) { -		reg_val |= 0x1; -		writel(reg_val, mmio + HOST_PORTS_IMPL); + +	ret = clk_prepare_enable(imxpriv->sata_ref_clk); +	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); + +		usleep_range(100, 200); + +		ret = imx_sata_phy_reset(hpriv); +		if (ret) { +			dev_err(dev, "failed to reset phy: %d\n", ret); +			goto disable_regulator; +		}  	} -	reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; -	writel(reg_val, mmio + HOST_TIMER1MS); +	usleep_range(1000, 2000);  	return 0; + +disable_regulator: +	if (hpriv->target_pwr) +		regulator_disable(hpriv->target_pwr); + +	return ret;  } -static void imx6q_sata_exit(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, +				   IMX6Q_GPR13_SATA_MPLL_CLK_EN, +				   !IMX6Q_GPR13_SATA_MPLL_CLK_EN); +	} -	regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN, -			!IMX6Q_GPR13_SATA_MPLL_CLK_EN);  	clk_disable_unprepare(imxpriv->sata_ref_clk); + +	if (hpriv->target_pwr) +		regulator_disable(hpriv->target_pwr); +} + +static void ahci_imx_error_handler(struct ata_port *ap) +{ +	u32 reg_val; +	struct ata_device *dev; +	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 = hpriv->plat_data; + +	ahci_error_handler(ap); + +	if (!(imxpriv->first_time) || ahci_imx_hotplug) +		return; + +	imxpriv->first_time = false; + +	ata_for_each_dev(dev, &ap->link, ENABLED) +		return; +	/* +	 * Disable link to save power.  An imx ahci port can't be recovered +	 * without full reset once the pddq mode is enabled making it +	 * impossible to use as part of libata LPM. +	 */ +	reg_val = readl(mmio + IMX_P0PHYCR); +	writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); +	imx_sata_disable(hpriv); +	imxpriv->no_device = true; + +	dev_info(ap->dev, "no device found, disabling link.\n"); +	dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ".hotplug=1 to enable hotplug\n");  } -static struct ahci_platform_data imx6q_sata_pdata = { -	.init = imx6q_sata_init, -	.exit = imx6q_sata_exit, +static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, +		       unsigned long deadline) +{ +	struct ata_port *ap = link->ap; +	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) +		ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); +	else if (imxpriv->type == AHCI_IMX6Q) +		ret = ahci_ops.softreset(link, class, deadline); + +	return ret; +} + +static struct ata_port_operations ahci_imx_ops = { +	.inherits	= &ahci_ops, +	.host_stop	= ahci_imx_host_stop, +	.error_handler	= ahci_imx_error_handler, +	.softreset	= ahci_imx_softreset, +}; + +static const struct ata_port_info ahci_imx_port_info = { +	.flags		= AHCI_FLAG_COMMON, +	.pio_mask	= ATA_PIO4, +	.udma_mask	= ATA_UDMA6, +	.port_ops	= &ahci_imx_ops,  };  static const struct of_device_id imx_ahci_of_match[] = { -	{ .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata}, +	{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, +	{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },  	{},  };  MODULE_DEVICE_TABLE(of, imx_ahci_of_match); @@ -131,101 +372,151 @@ 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; -	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; +  	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->ahci_pdev = pdev; +	imxpriv->no_device = false; +	imxpriv->first_time = true; +	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; +	imxpriv->sata_clk = devm_clk_get(dev, "sata"); +	if (IS_ERR(imxpriv->sata_clk)) { +		dev_err(dev, "can't get sata clock.\n"); +		return PTR_ERR(imxpriv->sata_clk);  	}  	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; +		return PTR_ERR(imxpriv->sata_ref_clk);  	} -	imxpriv->ahci_pdev = ahci_pdev; -	platform_set_drvdata(pdev, imxpriv); - -	of_id = of_match_device(imx_ahci_of_match, dev); -	if (of_id) { -		pdata = of_id->data; -	} else { -		ret = -EINVAL; -		goto err_out; +	imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); +	if (IS_ERR(imxpriv->ahb_clk)) { +		dev_err(dev, "can't get ahb clock.\n"); +		return PTR_ERR(imxpriv->ahb_clk);  	} -	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; +	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); +		}  	} -	res[0] = *mem; -	res[1] = *irq; +	hpriv = ahci_platform_get_resources(pdev); +	if (IS_ERR(hpriv)) +		return PTR_ERR(hpriv); -	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; +	hpriv->plat_data = imxpriv; -	ret = platform_device_add_resources(ahci_pdev, res, 2); +	ret = clk_prepare_enable(imxpriv->sata_clk);  	if (ret) -		goto err_out; +		return ret; -	ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata)); +	ret = imx_sata_enable(hpriv);  	if (ret) -		goto err_out; +		goto disable_clk; -	ret = platform_device_add(ahci_pdev); -	if (ret) { -err_out: -		platform_device_put(ahci_pdev); -		return ret; +	/* +	 * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, +	 * and IP vendor specific register IMX_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);  	} +	reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; +	writel(reg_val, hpriv->mmio + IMX_TIMER1MS); + +	ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, +				      0, 0, 0); +	if (ret) +		goto disable_sata; +  	return 0; + +disable_sata: +	imx_sata_disable(hpriv); +disable_clk: +	clk_disable_unprepare(imxpriv->sata_clk); +	return ret;  } -static int imx_ahci_remove(struct platform_device *pdev) +static void ahci_imx_host_stop(struct ata_host *host)  { -	struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev); -	struct platform_device *ahci_pdev = imxpriv->ahci_pdev; +	struct ahci_host_priv *hpriv = host->private_data; +	struct imx_ahci_priv *imxpriv = hpriv->plat_data; + +	imx_sata_disable(hpriv); +	clk_disable_unprepare(imxpriv->sata_clk); +} + +#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 = ahci_platform_suspend_host(dev); +	if (ret) +		return ret; + +	imx_sata_disable(hpriv); -	platform_device_unregister(ahci_pdev);  	return 0;  } +static int imx_ahci_resume(struct device *dev) +{ +	struct ata_host *host = dev_get_drvdata(dev); +	struct ahci_host_priv *hpriv = host->private_data; +	int ret; + +	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_mvebu.c b/drivers/ata/ahci_mvebu.c new file mode 100644 index 00000000000..fd3dfd733b8 --- /dev/null +++ b/drivers/ata/ahci_mvebu.c @@ -0,0 +1,128 @@ +/* + * AHCI glue platform driver for Marvell EBU SOCs + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * Marcin Wojtas <mw@semihalf.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/ahci_platform.h> +#include <linux/kernel.h> +#include <linux/mbus.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include "ahci.h" + +#define AHCI_VENDOR_SPECIFIC_0_ADDR  0xa0 +#define AHCI_VENDOR_SPECIFIC_0_DATA  0xa4 + +#define AHCI_WINDOW_CTRL(win)	(0x60 + ((win) << 4)) +#define AHCI_WINDOW_BASE(win)	(0x64 + ((win) << 4)) +#define AHCI_WINDOW_SIZE(win)	(0x68 + ((win) << 4)) + +static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv, +				   const struct mbus_dram_target_info *dram) +{ +	int i; + +	for (i = 0; i < 4; i++) { +		writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i)); +		writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i)); +		writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i)); +	} + +	for (i = 0; i < dram->num_cs; i++) { +		const struct mbus_dram_window *cs = dram->cs + i; + +		writel((cs->mbus_attr << 8) | +		       (dram->mbus_dram_target_id << 4) | 1, +		       hpriv->mmio + AHCI_WINDOW_CTRL(i)); +		writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i)); +		writel(((cs->size - 1) & 0xffff0000), +		       hpriv->mmio + AHCI_WINDOW_SIZE(i)); +	} +} + +static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) +{ +	/* +	 * Enable the regret bit to allow the SATA unit to regret a +	 * request that didn't receive an acknowlegde and avoid a +	 * deadlock +	 */ +	writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR); +	writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); +} + +static const struct ata_port_info ahci_mvebu_port_info = { +	.flags	   = AHCI_FLAG_COMMON, +	.pio_mask  = ATA_PIO4, +	.udma_mask = ATA_UDMA6, +	.port_ops  = &ahci_platform_ops, +}; + +static int ahci_mvebu_probe(struct platform_device *pdev) +{ +	struct ahci_host_priv *hpriv; +	const struct mbus_dram_target_info *dram; +	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; + +	dram = mv_mbus_dram_info(); +	if (!dram) +		return -ENODEV; + +	ahci_mvebu_mbus_config(hpriv, dram); +	ahci_mvebu_regret_option(hpriv); + +	rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, +				     0, 0, 0); +	if (rc) +		goto disable_resources; + +	return 0; + +disable_resources: +	ahci_platform_disable_resources(hpriv); +	return rc; +} + +static const struct of_device_id ahci_mvebu_of_match[] = { +	{ .compatible = "marvell,armada-380-ahci", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); + +/* + * We currently don't provide power management related operations, + * since there is no suspend/resume support at the platform level for + * Armada 38x for the moment. + */ +static struct platform_driver ahci_mvebu_driver = { +	.probe = ahci_mvebu_probe, +	.remove = ata_platform_remove_one, +	.driver = { +		.name = "ahci-mvebu", +		.owner = THIS_MODULE, +		.of_match_table = ahci_mvebu_of_match, +	}, +}; +module_platform_driver(ahci_mvebu_driver); + +MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver"); +MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Marcin Wojtas <mw@semihalf.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ahci_mvebu"); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 2daaee05cab..b10d81ddb52 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -12,134 +12,38 @@   * 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/of_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); - -static struct ata_port_operations ahci_platform_ops = { -	.inherits	= &ahci_ops, -	.host_stop	= ahci_host_stop, -}; - -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; +	unsigned long hflags = 0;  	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 = ahci_platform_get_resources(pdev); +	if (IS_ERR(hpriv)) +		return PTR_ERR(hpriv); -	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->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, @@ -150,69 +54,14 @@ static int ahci_probe(struct platform_device *pdev)  	if (pdata && pdata->init) {  		rc = pdata->init(dev, hpriv->mmio);  		if (rc) -			goto disable_unprepare_clk; +			goto disable_resources;  	} -	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 -		printk(KERN_INFO "ahci: 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; -	} - -	rc = ahci_reset_controller(host); -	if (rc) -		goto pdata_exit; - -	ahci_init_controller(host); -	ahci_print_info(host, "platform"); +	if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) +		hflags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; -	rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, -			       &ahci_platform_sht); +	rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, +				     hflags, 0, 0);  	if (rc)  		goto pdata_exit; @@ -220,114 +69,20 @@ 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", }, +	{ .compatible = "hisilicon,hisi-ahci", },  	{},  };  MODULE_DEVICE_TABLE(of, ahci_of_match); @@ -341,7 +96,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 00000000000..2595598df9c --- /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, 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 00000000000..02002f125bd --- /dev/null +++ b/drivers/ata/ahci_sunxi.c @@ -0,0 +1,252 @@ +/* + * 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 = { +	.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; +	unsigned long hflags; +	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; + +	hflags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | +		 AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; + +	rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, +				     hflags, 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 00000000000..ee3a3659bd9 --- /dev/null +++ b/drivers/ata/ahci_xgene.c @@ -0,0 +1,523 @@ +/* + * 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; +	u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ +	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_restart_engine - Restart the dma engine. + * @ap : ATA port of interest + * + * Restarts the dma engine inside the controller. + */ +static int xgene_ahci_restart_engine(struct ata_port *ap) +{ +	struct ahci_host_priv *hpriv = ap->host->private_data; + +	ahci_stop_engine(ap); +	ahci_start_fis_rx(ap); +	hpriv->start_engine(ap); + +	return 0; +} + +/** + * xgene_ahci_qc_issue - Issue commands to the device + * @qc: Command to issue + * + * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot + * clear the BSY bit after receiving the PIO setup FIS. This results in the dma + * state machine goes into the CMFatalErrorUpdate state and locks up. By + * restarting the dma engine, it removes the controller out of lock up state. + */ +static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) +{ +	struct ata_port *ap = qc->ap; +	struct ahci_host_priv *hpriv = ap->host->private_data; +	struct xgene_ahci_context *ctx = hpriv->plat_data; +	int rc = 0; + +	if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA)) +		xgene_ahci_restart_engine(ap); + +	rc = ahci_qc_issue(qc); + +	/* Save the last command issued */ +	ctx->last_cmd[ap->port_no] = qc->tf.command; + +	return rc; +} + +/** + * 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. + */ +static unsigned int xgene_ahci_read_id(struct ata_device *dev, +				       struct ata_taskfile *tf, u16 *id) +{ +	u32 err_mask; + +	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); + +	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, +	.qc_issue = xgene_ahci_qc_issue, +}; + +static const struct ata_port_info xgene_ahci_port_info = { +	.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; +	unsigned long hflags; +	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; +	} + +	hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; + +	rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, +				     hflags, 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 f8f38a08abc..9ff545ce8da 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> @@ -221,13 +220,6 @@ static struct pci_device_id ata_generic[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558), },  	{ PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE),  	  .driver_data = ATA_GEN_FORCE_DMA }, -	/* -	 * For some reason, MCP89 on MacBook 7,1 doesn't work with -	 * ahci, use ata_generic instead. -	 */ -	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA, -	  PCI_VENDOR_ID_APPLE, 0xcb89, -	  .driver_data = ATA_GEN_FORCE_DMA },  #if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE)  	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },  	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  }, @@ -249,7 +241,7 @@ static struct pci_driver ata_generic_pci_driver = {  	.id_table	= ata_generic,  	.probe 		= ata_generic_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 513ad7ed0c9..893e30e9a9e 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -100,7 +100,7 @@  enum {  	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */ -	ICH5_PMR		= 0x90, /* port mapping register */ +	ICH5_PMR		= 0x90, /* address map register */  	ICH5_PCS		= 0x92,	/* port control and status */  	PIIX_SIDPR_BAR		= 5,  	PIIX_SIDPR_LEN		= 16, @@ -233,7 +233,7 @@ static const struct pci_device_id piix_pci_tbl[] = {  	  PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich6m_sata },  	/* 82801GB/GR/GH (ICH7, identical to ICH6) */  	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, -	/* 2801GBM/GHM (ICH7M, identical to ICH6M) */ +	/* 82801GBM/GHM (ICH7M, identical to ICH6M)  */  	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata },  	/* Enterprise Southbridge 2 (631xESB/632xESB) */  	{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, @@ -517,7 +517,7 @@ static int ich_pata_cable_detect(struct ata_port *ap)  	const struct ich_laptop *lap = &ich_laptop[0];  	u8 mask; -	/* Check for specials - Acer Aspire 5602WLMi */ +	/* Check for specials */  	while (lap->device) {  		if (lap->device == pdev->device &&  		    lap->subvendor == pdev->subsystem_vendor && @@ -830,7 +830,7 @@ static bool piix_irq_check(struct ata_port *ap)  	return ap->ops->bmdma_status(ap) & ATA_DMA_INTR;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int piix_broken_suspend(void)  {  	static const struct dmi_system_id sysids[] = { @@ -1366,38 +1366,39 @@ static const int *piix_init_sata_map(struct pci_dev *pdev,  	const int *map;  	int i, invalid_map = 0;  	u8 map_value; +	char buf[32]; +	char *p = buf, *end = buf + sizeof(buf);  	pci_read_config_byte(pdev, ICH5_PMR, &map_value);  	map = map_db->map[map_value & map_db->mask]; -	dev_info(&pdev->dev, "MAP [");  	for (i = 0; i < 4; i++) {  		switch (map[i]) {  		case RV:  			invalid_map = 1; -			pr_cont(" XX"); +			p += scnprintf(p, end - p, " XX");  			break;  		case NA: -			pr_cont(" --"); +			p += scnprintf(p, end - p, " --");  			break;  		case IDE:  			WARN_ON((i & 1) || map[i + 1] != IDE);  			pinfo[i / 2] = piix_port_info[ich_pata_100];  			i++; -			pr_cont(" IDE IDE"); +			p += scnprintf(p, end - p, " IDE IDE");  			break;  		default: -			pr_cont(" P%d", map[i]); +			p += scnprintf(p, end - p, " P%d", map[i]);  			if (i & 1)  				pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;  			break;  		}  	} -	pr_cont(" ]\n"); +	dev_info(&pdev->dev, "MAP [%s ]\n", buf);  	if (invalid_map)  		dev_err(&pdev->dev, "invalid MAP value %u\n", map_value); @@ -1766,7 +1767,7 @@ static struct pci_driver piix_pci_driver = {  	.id_table		= piix_pci_tbl,  	.probe			= piix_init_one,  	.remove			= piix_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= piix_pci_device_suspend,  	.resume			= piix_pci_device_resume,  #endif diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index acfd0f71106..d72ce047030 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> @@ -69,7 +68,6 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,  static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);  static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);  static int ahci_port_start(struct ata_port *ap);  static void ahci_port_stop(struct ata_port *ap); @@ -89,7 +87,6 @@ static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,  static int ahci_hardreset(struct ata_link *link, unsigned int *class,  			  unsigned long deadline);  static void ahci_postreset(struct ata_link *link, unsigned int *class); -static void ahci_error_handler(struct ata_port *ap);  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);  static void ahci_dev_config(struct ata_device *dev);  #ifdef CONFIG_PM @@ -189,14 +186,15 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = {  };  EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); -int ahci_em_messages = 1; +static bool ahci_em_messages __read_mostly = true;  EXPORT_SYMBOL_GPL(ahci_em_messages); -module_param(ahci_em_messages, int, 0444); +module_param(ahci_em_messages, bool, 0444);  /* add other LED protocol types when they become supported */  MODULE_PARM_DESC(ahci_em_messages,  	"AHCI Enclosure Management Message control (0 = off, 1 = on)"); -int devslp_idle_timeout = 1000;	/* device sleep idle timeout in ms */ +/* device sleep idle timeout in ms */ +static int devslp_idle_timeout __read_mostly = 1000;  module_param(devslp_idle_timeout, int, 0644);  MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout"); @@ -394,6 +392,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.   */ @@ -450,11 +451,23 @@ void ahci_save_initial_config(struct device *dev,  		cap &= ~HOST_CAP_SNTF;  	} +	if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) { +		dev_info(dev, +			 "controller can't do DEVSLP, turning off\n"); +		cap2 &= ~HOST_CAP2_SDS; +		cap2 &= ~HOST_CAP2_SADM; +	} +  	if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) {  		dev_info(dev, "controller can do FBS, turning on CAP_FBS\n");  		cap |= HOST_CAP_FBS;  	} +	if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) { +		dev_info(dev, "controller can't do FBS, turning off CAP_FBS\n"); +		cap &= ~HOST_CAP_FBS; +	} +  	if (force_port_map && port_map != force_port_map) {  		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",  			 port_map, force_port_map); @@ -500,6 +513,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); @@ -603,7 +619,7 @@ int ahci_stop_engine(struct ata_port *ap)  }  EXPORT_SYMBOL_GPL(ahci_stop_engine); -static void ahci_start_fis_rx(struct ata_port *ap) +void ahci_start_fis_rx(struct ata_port *ap)  {  	void __iomem *port_mmio = ahci_port_base(ap);  	struct ahci_host_priv *hpriv = ap->host->private_data; @@ -629,6 +645,7 @@ static void ahci_start_fis_rx(struct ata_port *ap)  	/* flush */  	readl(port_mmio + PORT_CMD);  } +EXPORT_SYMBOL_GPL(ahci_start_fis_rx);  static int ahci_stop_fis_rx(struct ata_port *ap)  { @@ -766,7 +783,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) { @@ -778,8 +795,16 @@ static void ahci_start_port(struct ata_port *ap)  				rc = ap->ops->transmit_led_message(ap,  							       emp->led_state,  							       4); +				/* +				 * If busy, give a breather but do not +				 * release EH ownership by using msleep() +				 * instead of ata_msleep().  EM Transmit +				 * bit is busy for the whole host and +				 * releasing ownership will cause other +				 * ports to fail the same way. +				 */  				if (rc == -EBUSY) -					ata_msleep(ap, 1); +					msleep(1);  				else  					break;  			} @@ -1024,12 +1049,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; @@ -1226,7 +1252,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); @@ -1267,9 +1293,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  {  	struct ata_port *ap = link->ap;  	struct ahci_host_priv *hpriv = ap->host->private_data; +	struct ahci_port_priv *pp = ap->private_data;  	const char *reason = NULL;  	unsigned long now, msecs;  	struct ata_taskfile tf; +	bool fbs_disabled = false;  	int rc;  	DPRINTK("ENTER\n"); @@ -1279,6 +1307,16 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  	if (rc && rc != -EOPNOTSUPP)  		ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc); +	/* +	 * According to AHCI-1.2 9.3.9: if FBS is enable, software shall +	 * clear PxFBS.EN to '0' prior to issuing software reset to devices +	 * that is attached to port multiplier. +	 */ +	if (!ata_is_host_link(link) && pp->fbs_enabled) { +		ahci_disable_fbs(ap); +		fbs_disabled = true; +	} +  	ata_tf_init(link->device, &tf);  	/* issue the first D2H Register FIS */ @@ -1319,6 +1357,10 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  	} else  		*class = ahci_dev_classify(ap); +	/* re-enable FBS if disabled before */ +	if (fbs_disabled) +		ahci_enable_fbs(ap); +  	DPRINTK("EXIT, class=%u\n", *class);  	return 0; @@ -1363,8 +1405,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); @@ -1402,6 +1444,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; @@ -1419,7 +1462,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); @@ -1605,7 +1648,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; @@ -1740,7 +1783,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,  	}  } -void ahci_port_intr(struct ata_port *ap) +static void ahci_port_intr(struct ata_port *ap)  {  	void __iomem *port_mmio = ahci_port_base(ap);  	u32 status; @@ -1773,7 +1816,7 @@ irqreturn_t ahci_thread_fn(int irq, void *dev_instance)  }  EXPORT_SYMBOL_GPL(ahci_thread_fn); -void ahci_hw_port_interrupt(struct ata_port *ap) +static void ahci_hw_port_interrupt(struct ata_port *ap)  {  	void __iomem *port_mmio = ahci_port_base(ap);  	struct ahci_port_priv *pp = ap->private_data; @@ -1902,7 +1945,7 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)  }  EXPORT_SYMBOL_GPL(ahci_interrupt); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) +unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)  {  	struct ata_port *ap = qc->ap;  	void __iomem *port_mmio = ahci_port_base(ap); @@ -1931,6 +1974,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)  	return 0;  } +EXPORT_SYMBOL_GPL(ahci_qc_issue);  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)  { @@ -1981,12 +2025,14 @@ static void ahci_thaw(struct ata_port *ap)  	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);  } -static void ahci_error_handler(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); @@ -1994,6 +2040,7 @@ static void ahci_error_handler(struct ata_port *ap)  	if (!ata_dev_enabled(ap->link.device))  		ahci_stop_engine(ap);  } +EXPORT_SYMBOL_GPL(ahci_error_handler);  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)  { @@ -2006,6 +2053,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; @@ -2069,7 +2117,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, @@ -2081,6 +2129,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; @@ -2109,11 +2158,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; @@ -2141,7 +2191,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 00000000000..b0077589f06 --- /dev/null +++ b/drivers/ata/libahci_platform.c @@ -0,0 +1,549 @@ +/* + * 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 -ENOSYS: +			/* No PHY support. Check if PHY is required. */ +			if (of_find_property(dev->of_node, "phys", NULL)) { +				dev_err(dev, "couldn't get sata-phy: ENOSYS\n"); +				goto err_out; +			} +		case -ENODEV: +			/* 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 + * @host_flags: ahci host flags used in ahci_host_priv + * @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 long host_flags, +			    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 */ +	pi.private_data = (void *)host_flags; +	hpriv->flags |= host_flags; + +	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 4ba8b040557..97a14fe47de 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -20,8 +20,6 @@  #include <scsi/scsi_device.h>  #include "libata.h" -#include <acpi/acpi_bus.h> -  unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;  module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);  MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)"); @@ -40,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 @@ -123,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, @@ -156,59 +163,60 @@ 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)  { -	acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); +	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_handle) +	if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)  		return; -	ACPI_HANDLE_SET(&ap->tdev, acpi_get_child(host_handle, ap->port_no)); +	acpi_preset_companion(&ap->tdev, host_companion, ap->port_no);  	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)  {  	struct ata_port *ap = dev->link->ap; -	acpi_handle port_handle = ACPI_HANDLE(&ap->tdev); -	acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); -	acpi_handle parent_handle; +	struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); +	struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); +	struct acpi_device *parent, *adev; +	struct ata_acpi_hotplug_context *context;  	u64 adr;  	/* -	 * For both sata/pata devices, host handle is required. -	 * For pata device, port handle is also required. +	 * For both sata/pata devices, host companion device is required. +	 * For pata device, port companion device is also required.  	 */ -	if (libata_noacpi || !host_handle || -			(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle)) +	if (libata_noacpi || !host_companion || +			(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion))  		return;  	if (ap->flags & ATA_FLAG_ACPI_SATA) { @@ -216,16 +224,24 @@ void ata_acpi_bind_dev(struct ata_device *dev)  			adr = SATA_ADR(ap->port_no, NO_PORT_MULT);  		else  			adr = SATA_ADR(ap->port_no, dev->link->pmp); -		parent_handle = host_handle; +		parent = host_companion;  	} else {  		adr = dev->devno; -		parent_handle = port_handle; +		parent = port_companion;  	} -	ACPI_HANDLE_SET(&dev->tdev, acpi_get_child(parent_handle, adr)); +	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);  }  /** @@ -837,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;  		} @@ -1035,17 +1052,3 @@ void ata_acpi_on_disable(struct ata_device *dev)  {  	ata_acpi_clear_gtf(dev);  } - -void ata_scsi_acpi_bind(struct ata_device *dev) -{ -	acpi_handle handle = ata_dev_acpi_handle(dev); -	if (handle) -		acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev); -} - -void ata_scsi_acpi_unbind(struct ata_device *dev) -{ -	acpi_handle handle = ata_dev_acpi_handle(dev); -	if (handle) -		acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev); -} diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 83b1a9fb2d4..677c0c1b03b 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) @@ -2149,9 +2149,16 @@ static int ata_dev_config_ncq(struct ata_device *dev,  				    "failed to get NCQ Send/Recv Log Emask 0x%x\n",  				    err_mask);  		} else { +			u8 *cmds = dev->ncq_send_recv_cmds; +  			dev->flags |= ATA_DFLAG_NCQ_SEND_RECV; -			memcpy(dev->ncq_send_recv_cmds, ap->sector_buf, -				ATA_LOG_NCQ_SEND_RECV_SIZE); +			memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE); + +			if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) { +				ata_dev_dbg(dev, "disabling queued TRIM support\n"); +				cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &= +					~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM; +			}  		}  	} @@ -2215,6 +2222,16 @@ int ata_dev_configure(struct ata_device *dev)  	if (rc)  		return rc; +	/* some WD SATA-1 drives have issues with LPM, turn on NOLPM for them */ +	if ((dev->horkage & ATA_HORKAGE_WD_BROKEN_LPM) && +	    (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2) +		dev->horkage |= ATA_HORKAGE_NOLPM; + +	if (dev->horkage & ATA_HORKAGE_NOLPM) { +		ata_dev_warn(dev, "LPM support broken, forcing max_power\n"); +		dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER; +	} +  	/* let ACPI work its magic */  	rc = ata_acpi_on_devcfg(dev);  	if (rc) @@ -4126,6 +4143,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {  	{ "TORiSAN DVD-ROM DRD-N216", NULL,	ATA_HORKAGE_MAX_SEC_128 },  	{ "QUANTUM DAT    DAT72-000", NULL,	ATA_HORKAGE_ATAPI_MOD16_DMA },  	{ "Slimtype DVD A  DS8A8SH", NULL,	ATA_HORKAGE_MAX_SEC_LBA48 }, +	{ "Slimtype DVD A  DS8A9SH", NULL,	ATA_HORKAGE_MAX_SEC_LBA48 },  	/* Devices we expect to fail diagnostics */ @@ -4155,6 +4173,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {  	{ "ST3320[68]13AS",	"SD1[5-9]",	ATA_HORKAGE_NONCQ |  						ATA_HORKAGE_FIRMWARE_WARN }, +	/* 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 */  	{ "HTS541060G9SA00",    "MB3OC60D",     ATA_HORKAGE_NONCQ, }, @@ -4201,6 +4223,29 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {  	{ "PIONEER DVD-RW  DVR-212D",	NULL,	ATA_HORKAGE_NOSETXFER },  	{ "PIONEER DVD-RW  DVR-216D",	NULL,	ATA_HORKAGE_NOSETXFER }, +	/* devices that don't properly handle queued TRIM commands */ +	{ "Micron_M500*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM, }, +	{ "Crucial_CT???M500SSD*",	NULL,	ATA_HORKAGE_NO_NCQ_TRIM, }, +	{ "Micron_M550*",		NULL,	ATA_HORKAGE_NO_NCQ_TRIM, }, +	{ "Crucial_CT???M550SSD*",	NULL,	ATA_HORKAGE_NO_NCQ_TRIM, }, + +	/* +	 * Some WD SATA-I drives spin up and down erratically when the link +	 * is put into the slumber mode.  We don't have full list of the +	 * affected devices.  Disable LPM if the device matches one of the +	 * known prefixes and is SATA-1.  As a side effect LPM partial is +	 * lost too. +	 * +	 * https://bugzilla.kernel.org/show_bug.cgi?id=57211 +	 */ +	{ "WDC WD800JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD1200JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD1600JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD2000JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD2500JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD3000JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +	{ "WDC WD3200JD-*",		NULL,	ATA_HORKAGE_WD_BROKEN_LPM }, +  	/* End Marker */  	{ }  }; @@ -4742,6 +4787,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)   *	ata_qc_new - Request an available ATA command, for queueing   *	@ap: target port   * + *	Some ATA host controllers may implement a queue depth which is less + *	than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond + *	the hardware limitation. + *   *	LOCKING:   *	None.   */ @@ -4749,21 +4798,27 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)  static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)  {  	struct ata_queued_cmd *qc = NULL; -	unsigned int i; +	unsigned int max_queue = ap->host->n_tags; +	unsigned int i, tag;  	/* no command while frozen */  	if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))  		return NULL; -	/* the last tag is reserved for internal command. */ -	for (i = 0; i < ATA_MAX_QUEUE - 1; i++) -		if (!test_and_set_bit(i, &ap->qc_allocated)) { -			qc = __ata_qc_from_tag(ap, i); +	for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) { +		tag = tag < max_queue ? tag : 0; + +		/* the last tag is reserved for internal command. */ +		if (tag == ATA_TAG_INTERNAL) +			continue; + +		if (!test_and_set_bit(tag, &ap->qc_allocated)) { +			qc = __ata_qc_from_tag(ap, tag); +			qc->tag = tag; +			ap->last_tag = tag;  			break;  		} - -	if (qc) -		qc->tag = i; +	}  	return qc;  } @@ -5309,22 +5364,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);  	} @@ -5333,11 +5383,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; @@ -5348,87 +5393,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;  }  /* @@ -5457,21 +5496,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, @@ -5483,18 +5524,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 @@ -6053,6 +6093,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,  {  	spin_lock_init(&host->lock);  	mutex_init(&host->eh_mutex); +	host->n_tags = ATA_MAX_QUEUE - 1;  	host->dev = dev;  	host->ops = ops;  } @@ -6134,6 +6175,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)  {  	int i, rc; +	host->n_tags = clamp(sht->can_queue, 1, ATA_MAX_QUEUE - 1); +  	/* host must have been started */  	if (!(host->flags & ATA_HOST_STARTED)) {  		dev_err(host->dev, "BUG: trying to register unstarted host\n"); @@ -6279,6 +6322,8 @@ int ata_host_activate(struct ata_host *host, int irq,  static void ata_port_detach(struct ata_port *ap)  {  	unsigned long flags; +	struct ata_link *link; +	struct ata_device *dev;  	if (!ap->ops->error_handler)  		goto skip_eh; @@ -6298,15 +6343,21 @@ static void ata_port_detach(struct ata_port *ap)  	cancel_delayed_work_sync(&ap->hotplug_task);   skip_eh: +	/* clean up zpodd on port removal */ +	ata_for_each_link(link, ap, HOST_FIRST) { +		ata_for_each_dev(dev, link, ALL) { +			if (zpodd_dev_enabled(dev)) +				zpodd_exit(dev); +		} +	}  	if (ap->pmp_link) {  		int i;  		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)  			ata_tlink_delete(&ap->pmp_link[i]);  	} -	ata_tport_delete(ap); -  	/* remove the associated SCSI host */  	scsi_remove_host(ap->scsi_host); +	ata_tport_delete(ap);  }  /** @@ -6519,6 +6570,7 @@ static int __init ata_parse_force_one(char **cur,  		{ "norst",	.lflags		= ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },  		{ "rstonce",	.lflags		= ATA_LFLAG_RST_ONCE },  		{ "atapi_dmadir", .horkage_on	= ATA_HORKAGE_ATAPI_DMADIR }, +		{ "disable",	.horkage_on	= ATA_HORKAGE_DISABLE },  	};  	char *start = *cur, *p = *cur;  	char *id, *val, *endp; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c69fcce505c..dad83df555c 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 */  }; @@ -1322,14 +1323,14 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)   *	should be retried.  To be used from EH.   *   *	SCSI midlayer limits the number of retries to scmd->allowed. - *	scmd->retries is decremented for commands which get retried + *	scmd->allowed is incremented for commands which get retried   *	due to unrelated failures (qc->err_mask is zero).   */  void ata_eh_qc_retry(struct ata_queued_cmd *qc)  {  	struct scsi_cmnd *scmd = qc->scsicmd; -	if (!qc->err_mask && scmd->retries) -		scmd->retries--; +	if (!qc->err_mask) +		scmd->allowed++;  	__ata_eh_qc_complete(qc);  } @@ -1810,7 +1811,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,  	case ATA_DEV_ATA:  		if (err & ATA_ICRC)  			qc->err_mask |= AC_ERR_ATA_BUS; -		if (err & ATA_UNC) +		if (err & (ATA_UNC | ATA_AMNF))  			qc->err_mask |= AC_ERR_MEDIA;  		if (err & ATA_IDNF)  			qc->err_mask |= AC_ERR_INVALID; @@ -2293,6 +2294,7 @@ const char *ata_get_cmd_descript(u8 command)  		{ ATA_CMD_IDLE, 		"IDLE" },  		{ ATA_CMD_EDD, 			"EXECUTE DEVICE DIAGNOSTIC" },  		{ ATA_CMD_DOWNLOAD_MICRO,   	"DOWNLOAD MICROCODE" }, +		{ ATA_CMD_DOWNLOAD_MICRO_DMA,	"DOWNLOAD MICROCODE DMA" },  		{ ATA_CMD_NOP,			"NOP" },  		{ ATA_CMD_FLUSH, 		"FLUSH CACHE" },  		{ ATA_CMD_FLUSH_EXT, 		"FLUSH CACHE EXT" }, @@ -2313,6 +2315,8 @@ const char *ata_get_cmd_descript(u8 command)  		{ ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },  		{ ATA_CMD_FPDMA_READ,		"READ FPDMA QUEUED" },  		{ ATA_CMD_FPDMA_WRITE,		"WRITE FPDMA QUEUED" }, +		{ ATA_CMD_FPDMA_SEND,		"SEND FPDMA QUEUED" }, +		{ ATA_CMD_FPDMA_RECV,		"RECEIVE FPDMA QUEUED" },  		{ ATA_CMD_PIO_READ,		"READ SECTOR(S)" },  		{ ATA_CMD_PIO_READ_EXT,		"READ SECTOR(S) EXT" },  		{ ATA_CMD_PIO_WRITE,		"WRITE SECTOR(S)" }, @@ -2339,12 +2343,15 @@ const char *ata_get_cmd_descript(u8 command)  		{ ATA_CMD_WRITE_LOG_EXT,	"WRITE LOG EXT" },  		{ ATA_CMD_READ_LOG_DMA_EXT,	"READ LOG DMA EXT" },  		{ ATA_CMD_WRITE_LOG_DMA_EXT, 	"WRITE LOG DMA EXT" }, +		{ ATA_CMD_TRUSTED_NONDATA,	"TRUSTED NON-DATA" },  		{ ATA_CMD_TRUSTED_RCV,		"TRUSTED RECEIVE" },  		{ ATA_CMD_TRUSTED_RCV_DMA, 	"TRUSTED RECEIVE DMA" },  		{ ATA_CMD_TRUSTED_SND,		"TRUSTED SEND" },  		{ ATA_CMD_TRUSTED_SND_DMA, 	"TRUSTED SEND DMA" },  		{ ATA_CMD_PMP_READ,		"READ BUFFER" }, +		{ ATA_CMD_PMP_READ_DMA,		"READ BUFFER DMA" },  		{ ATA_CMD_PMP_WRITE,		"WRITE BUFFER" }, +		{ ATA_CMD_PMP_WRITE_DMA,	"WRITE BUFFER DMA" },  		{ ATA_CMD_CONF_OVERLAY,		"DEVICE CONFIGURATION OVERLAY" },  		{ ATA_CMD_SEC_SET_PASS,		"SECURITY SET PASSWORD" },  		{ ATA_CMD_SEC_UNLOCK,		"SECURITY UNLOCK" }, @@ -2363,6 +2370,8 @@ const char *ata_get_cmd_descript(u8 command)  		{ ATA_CMD_CFA_TRANS_SECT,	"CFA TRANSLATE SECTOR" },  		{ ATA_CMD_CFA_ERASE,		"CFA ERASE SECTORS" },  		{ ATA_CMD_CFA_WRITE_MULT_NE, 	"CFA WRITE MULTIPLE WITHOUT ERASE" }, +		{ ATA_CMD_REQ_SENSE_DATA,	"REQUEST SENSE DATA EXT" }, +		{ ATA_CMD_SANITIZE_DEVICE,	"SANITIZE DEVICE" },  		{ ATA_CMD_READ_LONG,		"READ LONG (with retries)" },  		{ ATA_CMD_READ_LONG_ONCE,	"READ LONG (without retries)" },  		{ ATA_CMD_WRITE_LONG,		"WRITE LONG (with retries)" }, @@ -2394,7 +2403,7 @@ static void ata_eh_link_report(struct ata_link *link)  	struct ata_port *ap = link->ap;  	struct ata_eh_context *ehc = &link->eh_context;  	const char *frozen, *desc; -	char tries_buf[6]; +	char tries_buf[6] = "";  	int tag, nr_failed = 0;  	if (ehc->i.flags & ATA_EHI_QUIET) @@ -2425,9 +2434,8 @@ static void ata_eh_link_report(struct ata_link *link)  	if (ap->pflags & ATA_PFLAG_FROZEN)  		frozen = " frozen"; -	memset(tries_buf, 0, sizeof(tries_buf));  	if (ap->eh_tries < ATA_EH_MAX_TRIES) -		snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d", +		snprintf(tries_buf, sizeof(tries_buf), " t%d",  			 ap->eh_tries);  	if (ehc->i.dev) { @@ -2548,11 +2556,12 @@ static void ata_eh_link_report(struct ata_link *link)  		}  		if (cmd->command != ATA_CMD_PACKET && -		    (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | -				     ATA_ABORTED))) -			ata_dev_err(qc->dev, "error: { %s%s%s%s}\n", +		    (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF | +				     ATA_IDNF | ATA_ABORTED))) +			ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n",  			  res->feature & ATA_ICRC ? "ICRC " : "",  			  res->feature & ATA_UNC ? "UNC " : "", +			  res->feature & ATA_AMNF ? "AMNF " : "",  			  res->feature & ATA_IDNF ? "IDNF " : "",  			  res->feature & ATA_ABORTED ? "ABRT " : "");  #endif @@ -3009,7 +3018,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap)  	 * ourselves at the beginning of each pass over the loop.  	 *  	 * Additionally, all write accesses to &ap->park_req_pending -	 * through INIT_COMPLETION() (see below) or complete_all() +	 * through reinit_completion() (see below) or complete_all()  	 * (see ata_scsi_park_store()) are protected by the host lock.  	 * As a result we have that park_req_pending.done is zero on  	 * exit from this function, i.e. when ATA_EH_PARK actions for @@ -3023,7 +3032,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap)  	 */  	spin_lock_irqsave(ap->lock, flags); -	INIT_COMPLETION(ap->park_req_pending); +	reinit_completion(&ap->park_req_pending);  	ata_for_each_link(link, ap, EDGE) {  		ata_for_each_dev(dev, link, ALL) {  			struct ata_eh_info *ehi = &link->eh_info; @@ -4062,7 +4071,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; @@ -4071,11 +4080,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; @@ -4127,13 +4131,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 20fd337a573..7ccc084bf1d 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-scsi.c b/drivers/ata/libata-scsi.c index 97a0cef1295..72691fd9394 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -111,12 +111,14 @@ static const char *ata_lpm_policy_names[] = {  	[ATA_LPM_MIN_POWER]	= "min_power",  }; -static ssize_t ata_scsi_lpm_store(struct device *dev, +static ssize_t ata_scsi_lpm_store(struct device *device,  				  struct device_attribute *attr,  				  const char *buf, size_t count)  { -	struct Scsi_Host *shost = class_to_shost(dev); +	struct Scsi_Host *shost = class_to_shost(device);  	struct ata_port *ap = ata_shost_to_port(shost); +	struct ata_link *link; +	struct ata_device *dev;  	enum ata_lpm_policy policy;  	unsigned long flags; @@ -132,10 +134,20 @@ static ssize_t ata_scsi_lpm_store(struct device *dev,  		return -EINVAL;  	spin_lock_irqsave(ap->lock, flags); + +	ata_for_each_link(link, ap, EDGE) { +		ata_for_each_dev(dev, &ap->link, ENABLED) { +			if (dev->horkage & ATA_HORKAGE_NOLPM) { +				count = -EOPNOTSUPP; +				goto out_unlock; +			} +		} +	} +  	ap->target_lpm_policy = policy;  	ata_port_schedule_eh(ap); +out_unlock:  	spin_unlock_irqrestore(ap->lock, flags); -  	return count;  } @@ -1981,7 +1993,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)  	memcpy(rbuf, hdr, sizeof(hdr));  	memcpy(&rbuf[8], "ATA     ", 8);  	ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); -	ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); + +	/* From SAT, use last 2 words from fw rev unless they are spaces */ +	ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); +	if (strncmp(&rbuf[32], "    ", 4) == 0) +		ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);  	if (rbuf[32] == 0 || rbuf[32] == ' ')  		memcpy(&rbuf[32], "n/a ", 4); @@ -3625,6 +3641,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)  		shost->max_lun = 1;  		shost->max_channel = 1;  		shost->max_cmd_len = 16; +		shost->no_write_same = 1;  		/* Schedule policy is determined by ->qc_defer()  		 * callback and it needs to see every deferred qc. @@ -3679,7 +3696,6 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)  			if (!IS_ERR(sdev)) {  				dev->sdev = sdev;  				scsi_device_put(sdev); -				ata_scsi_acpi_bind(dev);  			} else {  				dev->sdev = NULL;  			} @@ -3767,8 +3783,6 @@ static void ata_scsi_remove_dev(struct ata_device *dev)  	struct scsi_device *sdev;  	unsigned long flags; -	ata_scsi_acpi_unbind(dev); -  	/* Alas, we need to grab scan_mutex to ensure SCSI device  	 * state doesn't change underneath us and thus  	 * scsi_device_get() always succeeds.  The mutex locking can @@ -3874,6 +3888,27 @@ void ata_scsi_hotplug(struct work_struct *work)  		return;  	} +	/* +	 * XXX - UGLY HACK +	 * +	 * The block layer suspend/resume path is fundamentally broken due +	 * to freezable kthreads and workqueue and may deadlock if a block +	 * device gets removed while resume is in progress.  I don't know +	 * what the solution is short of removing freezable kthreads and +	 * workqueues altogether. +	 * +	 * The following is an ugly hack to avoid kicking off device +	 * removal while freezer is active.  This is a joke but does avoid +	 * this particular deadlock scenario. +	 * +	 * https://bugzilla.kernel.org/show_bug.cgi?id=62801 +	 * http://marc.info/?l=linux-kernel&m=138695698516487 +	 */ +#ifdef CONFIG_FREEZER +	while (pm_freezing) +		msleep(10); +#endif +  	DPRINTK("ENTER\n");  	mutex_lock(&ap->scsi_scan_mutex); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b603720b877..1121153f1ec 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2433,15 +2433,6 @@ int ata_pci_sff_activate_host(struct ata_host *host,  		mask = (1 << 2) | (1 << 0);  		if ((tmp8 & mask) != mask)  			legacy_mode = 1; -#if defined(CONFIG_NO_ATA_LEGACY) -		/* Some platforms with PCI limits cannot address compat -		   port space. In that case we punt if their firmware has -		   left a device in compatibility mode */ -		if (legacy_mode) { -			printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); -			return -EOPNOTSUPP; -		} -#endif  	}  	if (!devres_open_group(dev, NULL, GFP_KERNEL)) diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 150a917f0c3..e3741322822 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -321,25 +321,25 @@ int ata_tport_add(struct device *parent,  /*   * ATA link attributes   */ +static int noop(int x) { return x; } - -#define ata_link_show_linkspeed(field)					\ +#define ata_link_show_linkspeed(field, format)			        \  static ssize_t								\  show_ata_link_##field(struct device *dev,				\  		      struct device_attribute *attr, char *buf)		\  {									\  	struct ata_link *link = transport_class_to_link(dev);		\  									\ -	return sprintf(buf,"%s\n", sata_spd_string(fls(link->field)));	\ +	return sprintf(buf, "%s\n", sata_spd_string(format(link->field))); \  } -#define ata_link_linkspeed_attr(field)					\ -	ata_link_show_linkspeed(field)					\ +#define ata_link_linkspeed_attr(field, format)				\ +	ata_link_show_linkspeed(field, format)				\  static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL) -ata_link_linkspeed_attr(hw_sata_spd_limit); -ata_link_linkspeed_attr(sata_spd_limit); -ata_link_linkspeed_attr(sata_spd); +ata_link_linkspeed_attr(hw_sata_spd_limit, fls); +ata_link_linkspeed_attr(sata_spd_limit, fls); +ata_link_linkspeed_attr(sata_spd, noop);  static DECLARE_TRANSPORT_CLASS(ata_link_class, diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 68f9e3293e9..f3a65a3140d 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -85,23 +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; -	acpi_status status; -	struct acpi_device *acpi_dev; - -	handle = ata_dev_acpi_handle(ata_dev); -	if (!handle) -		return false; - -	status = acpi_bus_get_device(handle, &acpi_dev); -	if (ACPI_FAILURE(status)) -		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)  { @@ -269,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/libata.h b/drivers/ata/libata.h index eeeb77845d4..45b5ab3a95d 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -121,8 +121,6 @@ extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);  extern void ata_acpi_bind_port(struct ata_port *ap);  extern void ata_acpi_bind_dev(struct ata_device *dev);  extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev); -extern void ata_scsi_acpi_bind(struct ata_device *dev); -extern void ata_scsi_acpi_unbind(struct ata_device *dev);  #else  static inline void ata_acpi_dissociate(struct ata_host *host) { }  static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } @@ -133,8 +131,6 @@ static inline void ata_acpi_set_state(struct ata_port *ap,  				      pm_message_t state) { }  static inline void ata_acpi_bind_port(struct ata_port *ap) {}  static inline void ata_acpi_bind_dev(struct ata_device *dev) {} -static inline void ata_scsi_acpi_bind(struct ata_device *dev) {} -static inline void ata_scsi_acpi_unbind(struct ata_device *dev) {}  #endif  /* libata-scsi.c */ diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 73212c9c6d5..b70fce2a38e 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -7,16 +7,14 @@  #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>  #include <linux/gfp.h> -#include <scsi/scsi_host.h> -#include <acpi/acpi_bus.h> - +#include <linux/acpi.h>  #include <linux/libata.h>  #include <linux/ata.h> +#include <scsi/scsi_host.h>  #define DRV_NAME	"pata_acpi"  #define DRV_VERSION	"0.2.3" @@ -267,7 +265,7 @@ static struct pci_driver pacpi_pci_driver = {  	.id_table		= pacpi_pci_tbl,  	.probe			= pacpi_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 1b7b2ccabcf..d19cd88ed2d 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -589,7 +589,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  		return ata_pci_bmdma_init_one(pdev, ppi, &ali_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int ali_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -616,7 +616,7 @@ static struct pci_driver ali_pci_driver = {  	.id_table	= ali,  	.probe 		= ali_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ali_reinit_one,  #endif diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index d23e2b3ca0b..8d4d959a821 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> @@ -575,7 +574,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(pdev, ppi, &amd_sht, hpriv, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int amd_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -626,7 +625,7 @@ static struct pci_driver amd_pci_driver = {  	.id_table	= amd,  	.probe 		= amd_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= amd_reinit_one,  #endif diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 853f610af28..4edb1a81f63 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -319,6 +319,7 @@ static int cf_init(struct arasan_cf_dev *acdev)  	ret = clk_set_rate(acdev->clk, 166000000);  	if (ret) {  		dev_warn(acdev->host->dev, "clock set rate failed"); +		clk_disable_unprepare(acdev->clk);  		return ret;  	} @@ -355,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);  } @@ -396,8 +397,7 @@ dma_xfer(struct arasan_cf_dev *acdev, dma_addr_t src, dma_addr_t dest, u32 len)  	struct dma_async_tx_descriptor *tx;  	struct dma_chan *chan = acdev->dma_chan;  	dma_cookie_t cookie; -	unsigned long flags = DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | -		DMA_COMPL_SKIP_DEST_UNMAP; +	unsigned long flags = DMA_PREP_INTERRUPT;  	int ret = 0;  	tx = chan->device->device_prep_dma_memcpy(chan, dest, src, len, flags); @@ -898,9 +898,12 @@ static int arasan_cf_probe(struct platform_device *pdev)  	cf_card_detect(acdev, 0); -	return ata_host_activate(host, acdev->irq, irq_handler, 0, -			&arasan_cf_sht); +	ret = ata_host_activate(host, acdev->irq, irq_handler, 0, +				&arasan_cf_sht); +	if (!ret) +		return 0; +	cf_exit(acdev);  free_clk:  	clk_put(acdev->clk);  	return ret; diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 1581dee2967..96c05c9494f 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> @@ -423,7 +422,7 @@ static const struct pci_device_id artop_pci_tbl[] = {  	{ }	/* terminate list */  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int atp8xx_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -445,7 +444,7 @@ static struct pci_driver artop_pci_driver = {  	.id_table		= artop_pci_tbl,  	.probe			= artop_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= atp8xx_reinit_one,  #endif diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index d63ee8f41a4..8a66f23af4c 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> @@ -408,12 +407,13 @@ static int pata_at91_probe(struct platform_device *pdev)  	host->private_data = info; -	return ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0, -			gpio_is_valid(irq) ? ata_sff_interrupt : NULL, -			irq_flags, &pata_at91_sht); +	ret = ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0, +				gpio_is_valid(irq) ? ata_sff_interrupt : NULL, +				irq_flags, &pata_at91_sht); +	if (ret) +		goto err_put; -	if (!ret) -		return 0; +	return 0;  err_put:  	clk_put(info->mck); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 24e51056ac2..970f7767e5f 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> @@ -299,7 +298,7 @@ static struct pci_driver atiixp_pci_driver = {  	.id_table	= atiixp,  	.probe 		= atiixp_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.resume		= ata_pci_device_resume,  	.suspend	= ata_pci_device_suspend,  #endif diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c index 2ca5026f2c1..a705cfca90f 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> @@ -531,7 +530,7 @@ err_out:  	return rc;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int atp867x_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -559,7 +558,7 @@ static struct pci_driver atp867x_driver = {  	.id_table 	= atp867x_pci_tbl,  	.probe 		= atp867x_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= atp867x_reinit_one,  #endif diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index ba0d8a29dc2..03f2f2bc83b 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1619,7 +1619,7 @@ static int bfin_atapi_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)  {  	struct ata_host *host = platform_get_drvdata(pdev); diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 8fb69e5ca1b..c47caa807fa 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> @@ -232,7 +231,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int cmd640_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -257,7 +256,7 @@ static struct pci_driver cmd640_pci_driver = {  	.id_table	= cmd640,  	.probe 		= cmd640_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= cmd640_reinit_one,  #endif diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 1275a8d4ded..13ca5883285 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> @@ -488,7 +487,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int cmd64x_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -519,7 +518,7 @@ static struct pci_driver cmd64x_pci_driver = {  	.id_table	= cmd64x,  	.probe 		= cmd64x_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= cmd64x_reinit_one,  #endif diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index f10baabbf5d..d65cb9d2fa8 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> @@ -230,7 +229,7 @@ static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_host_register(host, &cs5520_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /**   *	cs5520_reinit_one	-	device resume   *	@pdev: PCI device @@ -279,7 +278,7 @@ static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)  	pci_save_state(pdev);  	return 0;  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  /* For now keep DMA off. We can set it for all but A rev CS5510 once the     core ATA code can handle it */ @@ -296,7 +295,7 @@ static struct pci_driver cs5520_pci_driver = {  	.id_table	= pata_cs5520,  	.probe 		= cs5520_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= cs5520_pci_device_suspend,  	.resume		= cs5520_reinit_one,  #endif diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index f07f2296acd..48ae4b43447 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> @@ -327,7 +326,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(pdev, ppi, &cs5530_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int cs5530_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -344,7 +343,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev)  	ata_host_resume(host);  	return 0;  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static const struct pci_device_id cs5530[] = {  	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, @@ -357,7 +356,7 @@ static struct pci_driver cs5530_pci_driver = {  	.id_table	= cs5530,  	.probe 		= cs5530_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= cs5530_reinit_one,  #endif diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 997e16a3a63..97584e8456d 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> @@ -201,7 +200,7 @@ static struct pci_driver cs5535_pci_driver = {  	.id_table	= cs5535,  	.probe 		= cs5535_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 0448860a207..6c15a554efb 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> @@ -298,7 +297,7 @@ static struct pci_driver cs5536_pci_driver = {  	.id_table	= cs5536,  	.probe		= cs5536_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 810bc9964dd..793018460d8 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> @@ -152,7 +151,7 @@ static struct pci_driver cy82c693_pci_driver = {  	.id_table	= cy82c693,  	.probe 		= cy82c693_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 3c12fd7acd4..4a57a6f032d 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> @@ -289,7 +288,7 @@ static struct pci_driver efar_pci_driver = {  	.id_table		= efar_pci_tbl,  	.probe			= efar_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index 980b88e109f..4d37c5415fc 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> @@ -709,8 +708,8 @@ static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)  	struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE  		? drv_data->dma_tx_channel : drv_data->dma_rx_channel; -	txd = channel->device->device_prep_slave_sg(channel, qc->sg, -		 qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL); +	txd = dmaengine_prep_slave_sg(channel, qc->sg, qc->n_elem, qc->dma_dir, +		DMA_CTRL_ACK);  	if (!txd) {  		dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");  		return; @@ -916,7 +915,7 @@ static int ep93xx_pata_probe(struct platform_device *pdev)  	struct ep93xx_pata_data *drv_data;  	struct ata_host *host;  	struct ata_port *ap; -	unsigned int irq; +	int irq;  	struct resource *mem_res;  	void __iomem *ide_base;  	int err; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 35b521348d3..cbc3de793d1 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> @@ -387,7 +386,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int hpt36x_reinit_one(struct pci_dev *dev)  {  	struct ata_host *host = pci_get_drvdata(dev); @@ -412,7 +411,7 @@ static struct pci_driver hpt36x_pci_driver = {  	.id_table	= hpt36x,  	.probe		= hpt36x_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= hpt36x_reinit_one,  #endif diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index a9d74eff5fc..3ba843f5cdc 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 4be0398c153..b93c0f0729e 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 85cf2861e0b..d019cdd5bc9 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> @@ -250,7 +249,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  				 IRQF_SHARED, &hpt3x3_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int hpt3x3_reinit_one(struct pci_dev *dev)  {  	struct ata_host *host = pci_get_drvdata(dev); @@ -278,7 +277,7 @@ static struct pci_driver hpt3x3_pci_driver = {  	.id_table	= hpt3x3,  	.probe 		= hpt3x3_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= hpt3x3_reinit_one,  #endif diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 26386f0b89a..af424573c2f 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;  	} @@ -189,7 +185,7 @@ static int pata_imx_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int pata_imx_suspend(struct device *dev)  {  	struct ata_host *host = dev_get_drvdata(dev); @@ -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); @@ -246,7 +244,7 @@ static struct platform_driver pata_imx_driver = {  		.name		= DRV_NAME,  		.of_match_table	= imx_pata_dt_ids,  		.owner		= THIS_MODULE, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  		.pm		= &pata_imx_pm_ops,  #endif  	}, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 4bceb8803a1..b33d1f99b3a 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -78,7 +78,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev  	ap->ioaddr.cmd_addr = cmd_addr; -	if (pnp_port_valid(idev, 1) == 0) { +	if (pnp_port_valid(idev, 1)) {  		ctl_addr = devm_ioport_map(&idev->dev,  					   pnp_port_start(idev, 1), 1);  		ap->ioaddr.altstatus_addr = ctl_addr; diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 2a8dd9527ec..4f97d1e52f8 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> @@ -284,7 +283,7 @@ static struct pci_driver it8213_pci_driver = {  	.id_table		= it8213_pci_tbl,  	.probe			= it8213_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 581e04d8036..a5088ecb349 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> @@ -936,7 +935,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(pdev, ppi, &it821x_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int it821x_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -966,7 +965,7 @@ static struct pci_driver it821x_pci_driver = {  	.id_table	= it821x,  	.probe 		= it821x_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= it821x_reinit_one,  #endif diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 1ec53f8ca96..ddf470c2341 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -144,6 +144,7 @@ static int ixp4xx_pata_probe(struct platform_device *pdev)  	struct ata_host *host;  	struct ata_port *ap;  	struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev); +	int ret;  	cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -157,7 +158,9 @@ static int ixp4xx_pata_probe(struct platform_device *pdev)  		return -ENOMEM;  	/* acquire resources and fill host */ -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);  	data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000); diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 76e739b031b..4d1a5d2c428 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> @@ -158,7 +157,7 @@ static struct pci_driver jmicron_pci_driver = {  	.id_table		= jmicron_pci_tbl,  	.probe			= jmicron_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index be816428b43..bce2a8ca467 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_macio.c b/drivers/ata/pata_macio.c index c28d0645e85..a02f76fdcfc 100644 --- a/drivers/ata/pata_macio.c +++ b/drivers/ata/pata_macio.c @@ -845,8 +845,7 @@ static int pata_macio_slave_config(struct scsi_device *sdev)  	return 0;  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int pata_macio_do_suspend(struct pata_macio_priv *priv, pm_message_t mesg)  {  	int rc; @@ -907,8 +906,7 @@ static int pata_macio_do_resume(struct pata_macio_priv *priv)  	return 0;  } - -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct scsi_host_template pata_macio_sht = {  	ATA_BASE_SHT(DRV_NAME), @@ -1208,8 +1206,7 @@ static int pata_macio_detach(struct macio_dev *mdev)  	return 0;  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int pata_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)  {  	struct ata_host *host = macio_get_drvdata(mdev); @@ -1223,8 +1220,7 @@ static int pata_macio_resume(struct macio_dev *mdev)  	return pata_macio_do_resume(host->private_data);  } - -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_PMAC_MEDIABAY  static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state) @@ -1316,8 +1312,7 @@ static void pata_macio_pci_detach(struct pci_dev *pdev)  	ata_host_detach(host);  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int pata_macio_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -1331,8 +1326,7 @@ static int pata_macio_pci_resume(struct pci_dev *pdev)  	return pata_macio_do_resume(host->private_data);  } - -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct of_device_id pata_macio_match[] =  { @@ -1360,7 +1354,7 @@ static struct macio_driver pata_macio_driver =  	},  	.probe		= pata_macio_attach,  	.remove		= pata_macio_detach, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= pata_macio_suspend,  	.resume		= pata_macio_resume,  #endif @@ -1383,7 +1377,7 @@ static struct pci_driver pata_macio_pci_driver = {  	.id_table	= pata_macio_pci_match,  	.probe		= pata_macio_pci_attach,  	.remove		= pata_macio_pci_detach, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= pata_macio_pci_suspend,  	.resume		= pata_macio_pci_resume,  #endif diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index a4f5e781c8c..ae9feb1ba8f 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> @@ -172,7 +171,7 @@ static struct pci_driver marvell_pci_driver = {  	.id_table		= marvell_pci_tbl,  	.probe			= marvell_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 0024ced3e20..ccd1c83a05c 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -819,9 +819,7 @@ mpc52xx_ata_remove(struct platform_device *op)  	return 0;  } - -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int  mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)  { @@ -847,10 +845,8 @@ mpc52xx_ata_resume(struct platform_device *op)  	return 0;  } -  #endif -  static struct of_device_id mpc52xx_ata_of_match[] = {  	{ .compatible = "fsl,mpc5200-ata", },  	{ .compatible = "mpc5200-ata", }, @@ -861,7 +857,7 @@ static struct of_device_id mpc52xx_ata_of_match[] = {  static struct platform_driver mpc52xx_ata_of_platform_driver = {  	.probe		= mpc52xx_ata_probe,  	.remove		= mpc52xx_ata_remove, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= mpc52xx_ata_suspend,  	.resume		= mpc52xx_ata_resume,  #endif diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 1f5f28bb0bb..202b4d60139 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> @@ -224,7 +223,7 @@ static struct pci_driver mpiix_pci_driver = {  	.id_table	= mpiix,  	.probe 		= mpiix_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index ad1a0febd62..0ea18331d46 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> @@ -93,7 +92,7 @@ static struct pci_driver netcell_pci_driver = {  	.id_table		= netcell_pci_tbl,  	.probe			= netcell_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c index 9513e071040..efb272da856 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> @@ -153,8 +152,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)  				 IRQF_SHARED, &ninja32_sht);  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int ninja32_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -184,7 +182,7 @@ static struct pci_driver ninja32_pci_driver = {  	.id_table	= ninja32,  	.probe 		= ninja32_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ninja32_reinit_one,  #endif diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 0c424dae56e..200e1eb23a2 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> @@ -162,7 +161,7 @@ static struct pci_driver ns87410_pci_driver = {  	.id_table	= ns87410,  	.probe 		= ns87410_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c index 16dc3a63a23..84c6b225b56 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> @@ -386,7 +385,7 @@ static const struct pci_device_id ns87415_pci_tbl[] = {  	{ }	/* terminate list */  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int ns87415_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -408,7 +407,7 @@ static struct pci_driver ns87415_pci_driver = {  	.id_table		= ns87415_pci_tbl,  	.probe			= ns87415_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ns87415_reinit_one,  #endif diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index c51bbb9ea8e..2a97d3a531e 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -865,7 +865,7 @@ static int octeon_cf_probe(struct platform_device *pdev)  	if (node == NULL)  		return -EINVAL; -	cf_port = kzalloc(sizeof(*cf_port), GFP_KERNEL); +	cf_port = devm_kzalloc(&pdev->dev, sizeof(*cf_port), GFP_KERNEL);  	if (!cf_port)  		return -ENOMEM; @@ -881,10 +881,9 @@ static int octeon_cf_probe(struct platform_device *pdev)  	n_size = of_n_size_cells(node);  	reg_prop = of_find_property(node, "reg", ®_len); -	if (!reg_prop || reg_len < sizeof(__be32)) { -		rv = -EINVAL; -		goto free_cf_port; -	} +	if (!reg_prop || reg_len < sizeof(__be32)) +		return -EINVAL; +  	cs_num = reg_prop->value;  	cf_port->cs0 = be32_to_cpup(cs_num); @@ -901,16 +900,13 @@ static int octeon_cf_probe(struct platform_device *pdev)  				res_dma = platform_get_resource(dma_dev, IORESOURCE_MEM, 0);  				if (!res_dma) {  					of_node_put(dma_node); -					rv = -EINVAL; -					goto free_cf_port; +					return -EINVAL;  				}  				cf_port->dma_base = (u64)devm_ioremap_nocache(&pdev->dev, res_dma->start,  									 resource_size(res_dma)); -  				if (!cf_port->dma_base) {  					of_node_put(dma_node); -					rv = -EINVAL; -					goto free_cf_port; +					return -EINVAL;  				}  				irq_handler = octeon_cf_interrupt; @@ -921,41 +917,34 @@ static int octeon_cf_probe(struct platform_device *pdev)  			of_node_put(dma_node);  		}  		res_cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); -		if (!res_cs1) { -			rv = -EINVAL; -			goto free_cf_port; -		} +		if (!res_cs1) +			return -EINVAL; +  		cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,  					   resource_size(res_cs1)); -  		if (!cs1) -			goto free_cf_port; +			return rv; + +		if (reg_len < (n_addr + n_size + 1) * sizeof(__be32)) +			return -EINVAL; -		if (reg_len < (n_addr + n_size + 1) * sizeof(__be32)) { -			rv = -EINVAL; -			goto free_cf_port; -		}  		cs_num += n_addr + n_size;  		cf_port->cs1 = be32_to_cpup(cs_num);  	}  	res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - -	if (!res_cs0) { -		rv = -EINVAL; -		goto free_cf_port; -	} +	if (!res_cs0) +		return -EINVAL;  	cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start,  				   resource_size(res_cs0)); -  	if (!cs0) -		goto free_cf_port; +		return rv;  	/* allocate host */  	host = ata_host_alloc(&pdev->dev, 1);  	if (!host) -		goto free_cf_port; +		return rv;  	ap = host->ports[0];  	ap->private_data = cf_port; @@ -1014,22 +1003,18 @@ static int octeon_cf_probe(struct platform_device *pdev)  	}  	cf_port->c0 = ap->ioaddr.ctl_addr; -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; +	rv = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); +	if (rv) +		return rv;  	ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr); -  	dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n",  		 is_16bit ? 16 : 8,  		 cf_port->is_true_ide ? ", True IDE" : "");  	return ata_host_activate(host, irq, irq_handler,  				 IRQF_SHARED, &octeon_cf_sht); - -free_cf_port: -	kfree(cf_port); -	return rv;  }  static void octeon_cf_shutdown(struct device *dev) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index d77b2e1054e..b9bf78b7d48 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> @@ -259,7 +258,7 @@ static struct pci_driver oldpiix_pci_driver = {  	.id_table		= oldpiix_pci_tbl,  	.probe			= oldpiix_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 4ea70cd22ae..3a944a02926 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> @@ -185,7 +184,7 @@ static struct pci_driver opti_pci_driver = {  	.id_table	= opti,  	.probe 		= opti_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 78ede3fd187..bdec7efa464 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> @@ -441,7 +440,7 @@ static struct pci_driver optidma_pci_driver = {  	.id_table	= optidma,  	.probe 		= optidma_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 40254f4df58..bcc4b968c04 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 9d874c85d64..4d06a5cda98 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> @@ -63,7 +62,7 @@ enum {  };  static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int pdc2027x_reinit_one(struct pci_dev *pdev);  #endif  static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline); @@ -129,7 +128,7 @@ static struct pci_driver pdc2027x_pci_driver = {  	.id_table		= pdc2027x_pci_tbl,  	.probe			= pdc2027x_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= pdc2027x_reinit_one,  #endif @@ -762,7 +761,7 @@ static int pdc2027x_init_one(struct pci_dev *pdev,  				 IRQF_SHARED, &pdc2027x_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int pdc2027x_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index c34fc50070a..9001991d283 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> @@ -378,7 +377,7 @@ static struct pci_driver pdc202xx_pci_driver = {  	.id_table	= pdc202xx,  	.probe 		= pdc202xx_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c index 2beb6b5045f..35cb0e26323 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> @@ -111,7 +110,7 @@ static struct pci_driver ata_tosh_pci_driver = {  	.id_table	= ata_tosh,  	.probe 		= ata_tosh_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 02794885de1..a5579b55e33 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 a6f05acad61..73259bfda1e 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 f582ba180a7..a3f1123d17a 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> @@ -238,7 +237,7 @@ static struct pci_driver radisys_pci_driver = {  	.id_table		= radisys_pci_tbl,  	.probe			= radisys_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c index 79a970f05a2..9ce5952216b 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> @@ -383,7 +382,7 @@ static struct pci_driver rdc_pci_driver = {  	.id_table		= rdc_pci_tbl,  	.probe			= rdc_init_one,  	.remove			= rdc_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 040b093617a..b3ec18c6bcc 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> @@ -102,7 +101,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en  	return -ENODEV;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int rz1000_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -134,7 +133,7 @@ static struct pci_driver rz1000_pci_driver = {  	.id_table	= pata_rz1000,  	.probe 		= rz1000_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= rz1000_reinit_one,  #endif diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 898e544a7ae..fb528831fb9 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -24,11 +24,34 @@  #include <linux/slab.h>  #include <linux/platform_data/ata-samsung_cf.h> -#include <plat/regs-ata.h>  #define DRV_NAME "pata_samsung_cf"  #define DRV_VERSION "0.1" +#define S3C_CFATA_REG(x)	(x) +#define S3C_CFATA_MUX		S3C_CFATA_REG(0x0) +#define S3C_ATA_CTRL		S3C_CFATA_REG(0x0) +#define S3C_ATA_CMD		S3C_CFATA_REG(0x8) +#define S3C_ATA_IRQ		S3C_CFATA_REG(0x10) +#define S3C_ATA_IRQ_MSK		S3C_CFATA_REG(0x14) +#define S3C_ATA_CFG		S3C_CFATA_REG(0x18) + +#define S3C_ATA_PIO_TIME	S3C_CFATA_REG(0x2c) +#define S3C_ATA_PIO_DTR		S3C_CFATA_REG(0x54) +#define S3C_ATA_PIO_FED		S3C_CFATA_REG(0x58) +#define S3C_ATA_PIO_SCR		S3C_CFATA_REG(0x5c) +#define S3C_ATA_PIO_LLR		S3C_CFATA_REG(0x60) +#define S3C_ATA_PIO_LMR		S3C_CFATA_REG(0x64) +#define S3C_ATA_PIO_LHR		S3C_CFATA_REG(0x68) +#define S3C_ATA_PIO_DVR		S3C_CFATA_REG(0x6c) +#define S3C_ATA_PIO_CSD		S3C_CFATA_REG(0x70) +#define S3C_ATA_PIO_DAD		S3C_CFATA_REG(0x74) +#define S3C_ATA_PIO_RDATA	S3C_CFATA_REG(0x7c) + +#define S3C_CFATA_MUX_TRUEIDE	0x01 +#define S3C_ATA_CFG_SWAP	0x40 +#define S3C_ATA_CFG_IORDYEN	0x02 +  enum s3c_cpu_type {  	TYPE_S3C64XX,  	TYPE_S5PC100, @@ -495,22 +518,10 @@ static int __init pata_s3c_probe(struct platform_device *pdev)  	info->irq = platform_get_irq(pdev, 0);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (res == NULL) { -		dev_err(dev, "failed to get mem resource\n"); -		return -EINVAL; -	} -	if (!devm_request_mem_region(dev, res->start, -				resource_size(res), DRV_NAME)) { -		dev_err(dev, "error requesting register region\n"); -		return -EBUSY; -	} - -	info->ide_addr = devm_ioremap(dev, res->start, resource_size(res)); -	if (!info->ide_addr) { -		dev_err(dev, "failed to map IO base address\n"); -		return -ENOMEM; -	} +	info->ide_addr = devm_ioremap_resource(dev, res); +	if (IS_ERR(info->ide_addr)) +		return PTR_ERR(info->ide_addr);  	info->clk = devm_clk_get(&pdev->dev, "cfcon");  	if (IS_ERR(info->clk)) { @@ -583,9 +594,13 @@ static int __init pata_s3c_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, host); -	return ata_host_activate(host, info->irq, -			info->irq ? pata_s3c_irq : NULL, -			0, &pata_s3c_sht); +	ret = ata_host_activate(host, info->irq, +				info->irq ? pata_s3c_irq : NULL, +				0, &pata_s3c_sht); +	if (ret) +		goto stop_clk; + +	return 0;  stop_clk:  	clk_disable(info->clk); @@ -604,7 +619,7 @@ static int __exit pata_s3c_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int pata_s3c_suspend(struct device *dev)  {  	struct platform_device *pdev = to_platform_device(dev); @@ -655,7 +670,7 @@ static struct platform_driver pata_s3c_driver = {  	.driver		= {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  		.pm	= &pata_s3c_pm_ops,  #endif  	}, diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index ce2f828c17b..c71de5d680d 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> @@ -255,7 +254,7 @@ static struct pci_driver sc1200_pci_driver = {  	.id_table	= sc1200,  	.probe 		= sc1200_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index f35f15f4d83..4e006d74bef 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> @@ -1097,7 +1096,7 @@ static struct pci_driver scc_pci_driver = {  	.id_table		= scc_pci_tbl,  	.probe			= scc_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c index d3830c45a36..b920c3407f8 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> @@ -65,7 +64,7 @@ static struct pci_driver sch_pci_driver = {  	.id_table		= sch_pci_tbl,  	.probe			= sch_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 96c6a79ef60..fc5f31d4828 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> @@ -437,7 +436,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id  	return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int serverworks_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -469,7 +468,7 @@ static struct pci_driver serverworks_pci_driver = {  	.id_table	= serverworks,  	.probe 		= serverworks_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= serverworks_reinit_one,  #endif diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c4b0b073ba8..f597edccede 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> @@ -404,7 +403,7 @@ use_ioports:  	return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sil680_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -430,7 +429,7 @@ static struct pci_driver sil680_pci_driver = {  	.id_table	= sil680,  	.probe 		= sil680_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= sil680_reinit_one,  #endif diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 1e8363640bf..626f989d5c6 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> @@ -870,7 +869,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)  	return ata_pci_bmdma_init_one(pdev, ppi, &sis_sht, chipset, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sis_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -900,7 +899,7 @@ static struct pci_driver sis_pci_driver = {  	.id_table		= sis_pci_tbl,  	.probe			= sis_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= sis_reinit_one,  #endif diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 6816911ac42..4935f61f629 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> @@ -338,7 +337,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id  	return ata_pci_bmdma_init_one(dev, ppi, &sl82c105_sht, NULL, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sl82c105_reinit_one(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -366,7 +365,7 @@ static struct pci_driver sl82c105_pci_driver = {  	.id_table	= sl82c105,  	.probe 		= sl82c105_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= sl82c105_reinit_one,  #endif diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 94473da68c0..d9364af8eb6 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> @@ -208,7 +207,7 @@ static const struct pci_device_id triflex[] = {  	{ },  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -234,7 +233,7 @@ static struct pci_driver triflex_pci_driver = {  	.id_table	= triflex,  	.probe 		= triflex_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= triflex_ata_pci_device_suspend,  	.resume		= ata_pci_device_resume,  #endif diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index c3ab9a6c396..1ca6bcab369 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> @@ -660,7 +659,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)  	return ata_pci_bmdma_init_one(pdev, ppi, &via_sht, (void *)config, 0);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /**   *	via_reinit_one		-	reinit after resume   *	@pdev; PCI device @@ -705,7 +704,7 @@ static struct pci_driver via_pci_driver = {  	.id_table	= via,  	.probe 		= via_init_one,  	.remove		= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= via_reinit_one,  #endif diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 8ea6e6afd04..f10631beffa 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 2e391730e8b..0bb2cabd219 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -29,8 +29,9 @@  #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>  #include <linux/of_platform.h>  #include <linux/platform_device.h>  #include <linux/libata.h> @@ -460,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_dwc_pmp.c b/drivers/ata/sata_dwc_pmp.c new file mode 100644 index 00000000000..3ff190af8d2 --- /dev/null +++ b/drivers/ata/sata_dwc_pmp.c @@ -0,0 +1,3041 @@ +/* + * drivers/ata/sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld@amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + *          Copyright 2006 Applied Micro Circuits Corporation + *          COPYRIGHT (C) 2005  SYNOPSYS, INC.  ALL RIGHTS RESERVED + * + * 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. + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/libata.h> +#include <linux/rtc.h> + +#include <scsi/scsi_host.h> +#include <scsi/scsi_cmnd.h> + + +#ifdef CONFIG_SATA_DWC_DEBUG +#define dwc_dev_dbg(dev, format, arg...) \ +	({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; }) +#define dwc_port_dbg(ap, format, arg...) \ +	ata_port_printk(ap, KERN_INFO, format, ##arg) +#define dwc_link_dbg(link, format, arg...) \ +	ata_link_printk(link, KERN_INFO, format, ##arg) +#else +#define dwc_dev_dbg(dev, format, arg...) \ +	({ 0; }) +#define dwc_port_dbg(ap, format, arg...) \ +	({ 0; }) +#define dwc_link_dbg(link, format, arg...) \ +	({ 0; }) +#endif + +#ifdef CONFIG_SATA_DWC_VDEBUG +#define DEBUG_NCQ +#define dwc_dev_vdbg(dev, format, arg...) \ +	({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; }) +#define dwc_port_vdbg(ap, format, arg...) \ +	ata_port_printk(ap, KERN_INFO, format, ##arg) +#define dwc_link_vdbg(link, format, arg...) \ +	ata_link_printk(link, KERN_INFO, format, ##arg) +#else +#define dwc_dev_vdbg(dev, format, arg...) \ +	({ 0; }) +#define dwc_port_vdbg(ap, format, arg...) \ +	({ 0; }) +#define dwc_link_vdbg(link, format, arg...) \ +	({ 0; }) +#endif + +#define dwc_dev_info(dev, format, arg...) \ +	({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; }) +#define dwc_port_info(ap, format, arg...) \ +	ata_port_printk(ap, KERN_INFO, format, ##arg) +#define dwc_link_info(link, format, arg...) \ +	ata_link_printk(link, KERN_INFO, format, ##arg) + +/* These two are defined in "libata.h" */ +#undef DRV_NAME +#undef DRV_VERSION +#define DRV_NAME        "sata-dwc" +#define DRV_VERSION     "2.0" + +/* Port Multiplier discovery Signature */ +#define PSCR_SCONTROL_DET_ENABLE	0x00000001 +#define PSCR_SSTATUS_DET_PRESENT	0x00000001 +#define PSCR_SERROR_DIAG_X		0x04000000 + +/* Port multiplier port entry in SCONTROL register */ +#define SCONTROL_PMP_MASK		0x000f0000 +#define PMP_TO_SCONTROL(p)		((p << 16) & 0x000f0000) +#define SCONTROL_TO_PMP(p)		(((p) & 0x000f0000) >> 16) + + +/* SATA DMA driver Globals */ +#if defined(CONFIG_APM821xx) +#define DMA_NUM_CHANS			2 +#else +#define DMA_NUM_CHANS			1 +#endif + +#define DMA_NUM_CHAN_REGS		8 + +/* SATA DMA Register definitions */ +#if defined(CONFIG_APM821xx) +#define AHB_DMA_BRST_DFLT       64  /* 16 data items burst length */ +#else +#define AHB_DMA_BRST_DFLT		64	/* 16 data items burst length */ +#endif + +#if defined(CONFIG_APOLLO3G) +extern void signal_hdd_led(int, int); +#endif +struct dmareg { +	u32 low;		/* Low bits 0-31 */ +	u32 high;		/* High bits 32-63 */ +}; + +/* DMA Per Channel registers */ + +struct dma_chan_regs { +	struct dmareg sar;	/* Source Address */ +	struct dmareg dar;	/* Destination address */ +	struct dmareg llp;	/* Linked List Pointer */ +	struct dmareg ctl;	/* Control */ +	struct dmareg sstat;	/* Source Status not implemented in core */ +	struct dmareg dstat;	/* Destination Status not implemented in core */ +	struct dmareg sstatar;	/* Source Status Address not impl in core */ +	struct dmareg dstatar;	/* Destination Status Address not implemented */ +	struct dmareg cfg;	/* Config */ +	struct dmareg sgr;	/* Source Gather */ +	struct dmareg dsr;	/* Destination Scatter */ +}; + +/* Generic Interrupt Registers */ +struct dma_interrupt_regs { +	struct dmareg tfr;	/* Transfer Interrupt */ +	struct dmareg block;	/* Block Interrupt */ +	struct dmareg srctran;	/* Source Transfer Interrupt */ +	struct dmareg dsttran;	/* Dest Transfer Interrupt */ +	struct dmareg error;	/* Error */ +}; + +struct ahb_dma_regs { +	struct dma_chan_regs	chan_regs[DMA_NUM_CHAN_REGS]; +	struct dma_interrupt_regs interrupt_raw;	/* Raw Interrupt */ +	struct dma_interrupt_regs interrupt_status;	/* Interrupt Status */ +	struct dma_interrupt_regs interrupt_mask;	/* Interrupt Mask */ +	struct dma_interrupt_regs interrupt_clear;	/* Interrupt Clear */ +	struct dmareg		statusInt;		/* Interrupt combined */ +	struct dmareg		rq_srcreg;		/* Src Trans Req */ +	struct dmareg		rq_dstreg;		/* Dst Trans Req */ +	struct dmareg		rq_sgl_srcreg;		/* Sngl Src Trans Req */ +	struct dmareg		rq_sgl_dstreg;		/* Sngl Dst Trans Req */ +	struct dmareg		rq_lst_srcreg;		/* Last Src Trans Req */ +	struct dmareg		rq_lst_dstreg;		/* Last Dst Trans Req */ +	struct dmareg		dma_cfg;		/* DMA Config */ +	struct dmareg		dma_chan_en;		/* DMA Channel Enable */ +	struct dmareg		dma_id;			/* DMA ID */ +	struct dmareg		dma_test;		/* DMA Test */ +	struct dmareg		res1;			/* reserved */ +	struct dmareg		res2;			/* reserved */ + +	/* DMA Comp Params +	 * Param 6 = dma_param[0], Param 5 = dma_param[1], +	 * Param 4 = dma_param[2] ... +	 */ +	struct dmareg		dma_params[6]; +}; + +/* Data structure for linked list item */ +struct lli { +	u32		sar;		/* Source Address */ +	u32		dar;		/* Destination address */ +	u32		llp;		/* Linked List Pointer */ +	struct dmareg	ctl;		/* Control */ +#if defined(CONFIG_APM821xx) +	u32             dstat;          /* Source status is not supported */ +#else +	struct dmareg	dstat;		/* Destination Status */ +#endif +}; + +#define SATA_DWC_DMAC_LLI_SZ		(sizeof(struct lli)) +#define SATA_DWC_DMAC_LLI_NUM		256 +#define SATA_DWC_DMAC_TWIDTH_BYTES	4 +#define SATA_DWC_DMAC_LLI_TBL_SZ	\ +	(SATA_DWC_DMAC_LLI_SZ * SATA_DWC_DMAC_LLI_NUM) +#if defined(CONFIG_APM821xx) +#define SATA_DWC_DMAC_CTRL_TSIZE_MAX    \ +        (0x00000800 * SATA_DWC_DMAC_TWIDTH_BYTES) +#else +#define SATA_DWC_DMAC_CTRL_TSIZE_MAX	\ +	(0x00000800 * SATA_DWC_DMAC_TWIDTH_BYTES) +#endif +/* DMA Register Operation Bits */ +#define DMA_EN              0x00000001		/* Enable AHB DMA */ +#define DMA_CHANNEL(ch)		(0x00000001 << (ch))	/* Select channel */ +#define DMA_ENABLE_CHAN(ch)	((0x00000001 << (ch)) |			\ +				 ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch)	(0x00000000 | ((0x000000001 << (ch)) << 8)) + +/* Channel Control Register */ +#define DMA_CTL_BLK_TS(size)	((size) & 0x000000FFF)	/* Blk Transfer size */ +#define DMA_CTL_LLP_SRCEN	0x10000000	/* Blk chain enable Src */ +#define DMA_CTL_LLP_DSTEN	0x08000000	/* Blk chain enable Dst */ +/* + * This define is used to set block chaining disabled in the control low + * register.  It is already in little endian format so it can be &'d dirctly. + * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN)) + */ +#define DMA_CTL_LLP_DISABLE_LE32 0xffffffe7 +#define DMA_CTL_SMS(num)	((num & 0x3) << 25)	/*Src Master Select*/ +#define DMA_CTL_DMS(num)	((num & 0x3) << 23)	/*Dst Master Select*/ +#define DMA_CTL_TTFC(type)	((type & 0x7) << 20)	/*Type&Flow cntr*/ +#define DMA_CTL_TTFC_P2M_DMAC	0x00000002		/*Per mem,DMAC cntr*/ +#define DMA_CTL_TTFC_M2P_PER	0x00000003		/*Mem per,peri cntr*/ +#define DMA_CTL_SRC_MSIZE(size)	((size & 0x7) << 14)	/*Src Burst Len*/ +#define DMA_CTL_DST_MSIZE(size)	((size & 0x7) << 11)	/*Dst Burst Len*/ +#define DMA_CTL_SINC_INC	0x00000000		/*Src addr incr*/ +#define DMA_CTL_SINC_DEC	0x00000200 +#define DMA_CTL_SINC_NOCHANGE	0x00000400 +#define DMA_CTL_DINC_INC	0x00000000		/*Dst addr incr*/ +#define DMA_CTL_DINC_DEC	0x00000080 +#define DMA_CTL_DINC_NOCHANGE	0x00000100 +#define DMA_CTL_SRC_TRWID(size)	((size & 0x7) << 4)	/*Src Trnsfr Width*/ +#define DMA_CTL_DST_TRWID(size)	((size & 0x7) << 1)	/*Dst Trnsfr Width*/ +#define DMA_CTL_INT_EN		0x00000001		/*Interrupt Enable*/ + +/* Channel Configuration Register high bits */ +#define DMA_CFG_FCMOD_REQ	0x00000001		/*Flow cntrl req*/ +#define DMA_CFG_PROTCTL		(0x00000003 << 2)	/*Protection cntrl*/ + +/* Channel Configuration Register low bits */ +#define DMA_CFG_RELD_DST	0x80000000		/*Reload Dst/Src Addr*/ +#define DMA_CFG_RELD_SRC	0x40000000 +#define DMA_CFG_HS_SELSRC	0x00000800		/*SW hndshk Src/Dst*/ +#define DMA_CFG_HS_SELDST	0x00000400 +#define DMA_CFG_FIFOEMPTY       (0x00000001 << 9)	/*FIFO Empty bit*/ + +/* Assign hardware handshaking interface (x) to dst / sre peripheral */ +#define DMA_CFG_HW_HS_DEST(int_num)	((int_num & 0xF) << 11) +#define DMA_CFG_HW_HS_SRC(int_num)	((int_num & 0xF) << 7) + +/* Channel Linked List Pointer Register */ +#define DMA_LLP_LMS(addr, master)	(((addr) & 0xfffffffc) | (master)) +#define DMA_LLP_AHBMASTER1		0	/* List Master Select */ +#define DMA_LLP_AHBMASTER2		1 + +#define SATA_DWC_MAX_PORTS	1 + +#define SATA_DWC_SCR_OFFSET	0x24 +#define SATA_DWC_REG_OFFSET	0x64 + +/* DWC SATA Registers */ +struct sata_dwc_regs { +	u32 fptagr;		/* 1st party DMA tag */ +	u32 fpbor;		/* 1st party DMA buffer offset */ +	u32 fptcr;		/* 1st party DMA Xfr count */ +	u32 dmacr;		/* DMA Control */ +	u32 dbtsr;		/* DMA Burst Transac size */ +	u32 intpr;		/* Interrupt Pending */ +	u32 intmr;		/* Interrupt Mask */ +	u32 errmr;		/* Error Mask */ +	u32 llcr;		/* Link Layer Control */ +	u32 phycr;		/* PHY Control */ +	u32 physr;		/* PHY Status */ +	u32 rxbistpd;		/* Recvd BIST pattern def register */ +	u32 rxbistpd1;		/* Recvd BIST data dword1 */ +	u32 rxbistpd2;		/* Recvd BIST pattern data dword2 */ +	u32 txbistpd;		/* Trans BIST pattern def register */ +	u32 txbistpd1;		/* Trans BIST data dword1 */ +	u32 txbistpd2;		/* Trans BIST data dword2 */ +	u32 bistcr;		/* BIST Control Register */ +	u32 bistfctr;		/* BIST FIS Count Register */ +	u32 bistsr;		/* BIST Status Register */ +	u32 bistdecr;		/* BIST Dword Error count register */ +	u32 res[15];		/* Reserved locations */ +	u32 testr;		/* Test Register */ +	u32 versionr;		/* Version Register */ +	u32 idr;		/* ID Register */ +	u32 unimpl[192];	/* Unimplemented */ +	u32 dmadr[256];	/* FIFO Locations in DMA Mode */ +}; + +#define SCR_SCONTROL_DET_ENABLE		0x00000001 +#define SCR_SSTATUS_DET_PRESENT		0x00000001 +#define SCR_SERROR_DIAG_X		0x04000000 + +/* DWC SATA Register Operations */ +#define	SATA_DWC_TXFIFO_DEPTH		0x01FF +#define	SATA_DWC_RXFIFO_DEPTH		0x01FF + +#define SATA_DWC_DMACR_TMOD_TXCHEN	0x00000004 +#define	SATA_DWC_DMACR_TXCHEN		(0x00000001 | \ +						SATA_DWC_DMACR_TMOD_TXCHEN) +#define	SATA_DWC_DMACR_RXCHEN		(0x00000002 | \ +						SATA_DWC_DMACR_TMOD_TXCHEN) +#define SATA_DWC_DMACR_TX_CLEAR(v)	(((v) & ~SATA_DWC_DMACR_TXCHEN) | \ +						SATA_DWC_DMACR_TMOD_TXCHEN) +#define SATA_DWC_DMACR_RX_CLEAR(v)	(((v) & ~SATA_DWC_DMACR_RXCHEN) | \ +						SATA_DWC_DMACR_TMOD_TXCHEN) +#define SATA_DWC_DMACR_TXRXCH_CLEAR	SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_DBTSR_MWR(size)	((size/4) & \ +						SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size)	(((size/4) & \ +						SATA_DWC_RXFIFO_DEPTH) << 16) + +// SATA DWC Interrupts +#define	SATA_DWC_INTPR_DMAT			0x00000001 +#define SATA_DWC_INTPR_NEWFP		0x00000002 +#define SATA_DWC_INTPR_PMABRT		0x00000004 +#define SATA_DWC_INTPR_ERR			0x00000008 +#define SATA_DWC_INTPR_NEWBIST		0x00000010 +#define SATA_DWC_INTPR_IPF			0x80000000 +// Interrupt masks +#define	SATA_DWC_INTMR_DMATM		0x00000001 +#define SATA_DWC_INTMR_NEWFPM		0x00000002 +#define SATA_DWC_INTMR_PMABRTM		0x00000004 +#define SATA_DWC_INTMR_ERRM			0x00000008 +#define SATA_DWC_INTMR_NEWBISTM		0x00000010 +#define SATA_DWC_INTMR_PRIMERRM		0x00000020 +#define SATA_DWC_INTPR_CMDGOOD		0x00000080 +#define SATA_DWC_INTPR_CMDABORT		0x00000040 + +#define SATA_DWC_LLCR_SCRAMEN		0x00000001 +#define SATA_DWC_LLCR_DESCRAMEN		0x00000002 +#define SATA_DWC_LLCR_RPDEN			0x00000004 + +// Defines for SError register +#define SATA_DWC_SERR_ERRI      0x00000001 // Recovered data integrity error +#define SATA_DWC_SERR_ERRM      0x00000002 // Recovered communication error +#define SATA_DWC_SERR_ERRT      0x00000100 // Non-recovered transient data integrity error +#define SATA_DWC_SERR_ERRC      0x00000200 // Non-recovered persistent communication or data integrity error +#define SATA_DWC_SERR_ERRP      0x00000400 // Protocol error +#define SATA_DWC_SERR_ERRE      0x00000800 // Internal host adapter error +#define SATA_DWC_SERR_DIAGN     0x00010000 // PHYRdy change +#define SATA_DWC_SERR_DIAGI     0x00020000 // PHY internal error +#define SATA_DWC_SERR_DIAGW     0x00040000 // Phy COMWAKE signal is detected +#define SATA_DWC_SERR_DIAGB     0x00080000 // 10b to 8b decoder err +#define SATA_DWC_SERR_DIAGT     0x00100000 // Disparity error +#define SATA_DWC_SERR_DIAGC		0x00200000 // CRC error +#define SATA_DWC_SERR_DIAGH		0x00400000 // Handshake error +#define SATA_DWC_SERR_DIAGL		0x00800000 // Link sequence (illegal transition) error +#define SATA_DWC_SERR_DIAGS		0x01000000 // Transport state transition error +#define SATA_DWC_SERR_DIAGF		0x02000000 // Unrecognized FIS type +#define SATA_DWC_SERR_DIAGX		0x04000000 // Exchanged error - Set when PHY COMINIT signal is detected. +#define SATA_DWC_SERR_DIAGA		0x08000000 // Port Selector Presence detected + +/* This is all error bits, zero's are reserved fields. */ +#define SATA_DWC_SERR_ERR_BITS	0x0FFF0F03 + +#define SATA_DWC_SCR0_SPD_GET(v)	((v >> 4) & 0x0000000F) + +struct sata_dwc_device { +	struct resource reg;            /* Resource for register */ +	struct device		*dev;		/* generic device struct */ +	struct ata_probe_ent	*pe;		/* ptr to probe-ent */ +	struct ata_host		*host; +	u8			*reg_base; +	struct sata_dwc_regs	*sata_dwc_regs;	/* DW Synopsys SATA specific */ +	u8     			*scr_base; +	int    			dma_channel;	/* DWC SATA DMA channel  */ +	int			irq_dma; +	struct timer_list an_timer; +}; + +#define SATA_DWC_QCMD_MAX	32 + +struct sata_dwc_device_port { +	struct sata_dwc_device	*hsdev; +	int			cmd_issued[SATA_DWC_QCMD_MAX]; +	struct lli		*llit[SATA_DWC_QCMD_MAX]; +	dma_addr_t		llit_dma[SATA_DWC_QCMD_MAX]; +	u32			dma_chan[SATA_DWC_QCMD_MAX]; +	int			dma_pending[SATA_DWC_QCMD_MAX]; +	u32 			sata_dwc_sactive_issued;	/* issued queued ops */ +	u32 			sata_dwc_sactive_queued;	/* queued ops */ +	u32 			dma_interrupt_count; + +}; + +static struct sata_dwc_device* dwc_dev_list[2]; +static int dma_intr_registered = 0; +/* + * Commonly used DWC SATA driver Macros + */ +#define HSDEV_FROM_HOST(host)	((struct sata_dwc_device *) \ +					(host)->private_data) +#define HSDEV_FROM_AP(ap)	((struct sata_dwc_device *) \ +					(ap)->host->private_data) +#define HSDEVP_FROM_AP(ap)	((struct sata_dwc_device_port *) \ +					(ap)->private_data) +#define HSDEV_FROM_QC(qc)	((struct sata_dwc_device *) \ +					(qc)->ap->host->private_data) +#define HSDEV_FROM_HSDEVP(p)	((struct sata_dwc_device *) \ +					(hsdevp)->hsdev) + +enum { +	SATA_DWC_CMD_ISSUED_NOT		= 0, +	SATA_DWC_CMD_ISSUED_PENDING	= 1, +	SATA_DWC_CMD_ISSUED_EXEC	= 2, +	SATA_DWC_CMD_ISSUED_NODATA	= 3, + +	SATA_DWC_DMA_PENDING_NONE	= 0, +	SATA_DWC_DMA_PENDING_TX		= 1, +	SATA_DWC_DMA_PENDING_RX		= 2, +}; + +/* + * Globals + */ +static struct ahb_dma_regs *sata_dma_regs = 0; + +/* + * Prototypes + */ +static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag); +static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, +				u32 check_status); +static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status); +static void sata_dwc_port_stop(struct ata_port *ap); +static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag); + +static int dma_dwc_init(struct sata_dwc_device *hsdev); +static void dma_dwc_exit(struct sata_dwc_device *hsdev); +static int dma_dwc_xfer_setup(struct ata_queued_cmd *qc, +			      struct lli *lli, dma_addr_t dma_lli, +			      void __iomem *addr); +static void dma_dwc_xfer_start(int dma_ch); +static void dma_dwc_terminate_dma(struct ata_port *ap, int dma_ch); +static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev); +static void sata_dwc_init_port ( struct ata_port *ap ); +u8 sata_dwc_check_status(struct ata_port *ap); + + + + +static const char *dir_2_txt(enum dma_data_direction dir) +{ +	switch (dir) { +	case DMA_BIDIRECTIONAL: +		return "bi"; +	case DMA_FROM_DEVICE: +		return "from"; +	case DMA_TO_DEVICE: +		return "to"; +	case DMA_NONE: +		return "none"; +	default: +		return "err"; +	} +} + +static const char *prot_2_txt(enum ata_tf_protocols protocol) +{ +	switch (protocol) { +	case ATA_PROT_UNKNOWN: +		return "unknown"; +	case ATA_PROT_NODATA: +		return "nodata"; +	case ATA_PROT_PIO: +		return "pio"; +	case ATA_PROT_DMA: +		return "dma"; +	case ATA_PROT_NCQ: +		return "ncq"; +	case ATAPI_PROT_PIO: +		return "atapi pio"; +	case ATAPI_PROT_NODATA: +		return "atapi nodata"; +	case ATAPI_PROT_DMA: +		return "atapi dma"; +	default: +		return "err"; +	} +} + +inline const char *ata_cmd_2_txt(const struct ata_taskfile *tf) +{ +	switch (tf->command) { +	case ATA_CMD_CHK_POWER: +		return "ATA_CMD_CHK_POWER"; +	case ATA_CMD_EDD: +		return "ATA_CMD_EDD"; +	case ATA_CMD_FLUSH: +		return "ATA_CMD_FLUSH"; +	case ATA_CMD_FLUSH_EXT: +		return "ATA_CMD_FLUSH_EXT"; +	case ATA_CMD_ID_ATA: +		return "ATA_CMD_ID_ATA"; +	case ATA_CMD_ID_ATAPI: +		return "ATA_CMD_ID_ATAPI"; +	case ATA_CMD_FPDMA_READ: +		return "ATA_CMD_FPDMA_READ"; +	case ATA_CMD_FPDMA_WRITE: +		return "ATA_CMD_FPDMA_WRITE"; +	case ATA_CMD_READ: +		return "ATA_CMD_READ"; +	case ATA_CMD_READ_EXT: +		return "ATA_CMD_READ_EXT"; +	case ATA_CMD_READ_NATIVE_MAX_EXT : +		return "ATA_CMD_READ_NATIVE_MAX_EXT"; +	case ATA_CMD_VERIFY_EXT : +		return "ATA_CMD_VERIFY_EXT"; +	case ATA_CMD_WRITE: +		return "ATA_CMD_WRITE"; +	case ATA_CMD_WRITE_EXT: +		return "ATA_CMD_WRITE_EXT"; +	case ATA_CMD_PIO_READ: +		return "ATA_CMD_PIO_READ"; +	case ATA_CMD_PIO_READ_EXT: +		return "ATA_CMD_PIO_READ_EXT"; +	case ATA_CMD_PIO_WRITE: +		return "ATA_CMD_PIO_WRITE"; +	case ATA_CMD_PIO_WRITE_EXT: +		return "ATA_CMD_PIO_WRITE_EXT"; +	case ATA_CMD_SET_FEATURES: +		return "ATA_CMD_SET_FEATURES"; +	case ATA_CMD_PACKET: +		return "ATA_CMD_PACKET"; +	case ATA_CMD_PMP_READ: +		return "ATA_CMD_PMP_READ"; +	case ATA_CMD_PMP_WRITE: +		return "ATA_CMD_PMP_WRITE"; +	default: +		return "ATA_CMD_???"; +	} +} + +/*  + * Dump content of the taskfile + */ +static void sata_dwc_tf_dump(struct device *dwc_dev, struct ata_taskfile *tf) +{ +	dwc_dev_vdbg(dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags: 0x%lx" +			"device: %x\n", tf->command, prot_2_txt(tf->protocol), +			tf->flags, tf->device); +	dwc_dev_vdbg(dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x lbam:" +			"0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal, +			tf->lbam, tf->lbah); +	dwc_dev_vdbg(dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x hob_lbal: 0x%x " +			"hob_lbam: 0x%x hob_lbah: 0x%x\n", tf->hob_feature, +			tf->hob_nsect, tf->hob_lbal, tf->hob_lbam, +			tf->hob_lbah); +} + +/* + * Function: get_burst_length_encode + * arguments: datalength: length in bytes of data + * returns value to be programmed in register corresponding to data length + * This value is effectively the log(base 2) of the length + */ +static inline int get_burst_length_encode(int datalength) +{ +	int items = datalength >> 2;	/* div by 4 to get lword count */ + +	if (items >= 64) +		return 5; + +	if (items >= 32) +		return 4; + +	if (items >= 16) +		return 3; + +	if (items >= 8) +		return 2; + +	if (items >= 4) +		return 1; + +	return 0; +} + +/* + * Clear Interrupts on a DMA channel + */ +static inline void clear_chan_interrupts(int c) +{ +	out_le32(&(sata_dma_regs->interrupt_clear.tfr.low), DMA_CHANNEL(c)); +	out_le32(&(sata_dma_regs->interrupt_clear.block.low), DMA_CHANNEL(c)); +	out_le32(&(sata_dma_regs->interrupt_clear.srctran.low), DMA_CHANNEL(c)); +	out_le32(&(sata_dma_regs->interrupt_clear.dsttran.low), DMA_CHANNEL(c)); +	out_le32(&(sata_dma_regs->interrupt_clear.error.low), DMA_CHANNEL(c)); +} + +/* + * Function: dma_request_channel + * arguments: None + * returns channel number if available else -1 + * This function assigns the next available DMA channel from the list to the + * requester + */ +static int dma_request_channel(struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + +	if (!(in_le32(&(sata_dma_regs->dma_chan_en.low)) & DMA_CHANNEL(hsdev->dma_channel))) { +		dwc_port_vdbg(ap, "%s Successfully requested DMA channel %d\n",  +				__func__, hsdev->dma_channel); +		return (hsdev->dma_channel); +	} +	 +	return -1; +} + + + +/* + * Function: dma_dwc_interrupt + * arguments: irq, dev_id, pt_regs + * returns channel number if available else -1 + * Interrupt Handler for DW AHB SATA DMA + */ +static int dma_dwc_interrupt(int irq, void *hsdev_instance) +{ +	volatile u32 tfr_reg, err_reg; +	unsigned long flags; +	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; +	u8 tag = 0; +	int chan; +	unsigned int port = 0; +	spin_lock_irqsave(&host->lock, flags); + +	ap = host->ports[port]; +	hsdevp = HSDEVP_FROM_AP(ap); +	tag = ap->link.active_tag; + +	dwc_port_vdbg(ap, "%s: DMA interrupt in channel %d\n", __func__, hsdev->dma_channel); + +	tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low)); +	err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low)); + +	dwc_port_vdbg(ap, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", +		tfr_reg, err_reg, hsdevp->dma_pending[tag], port); +	chan = hsdev->dma_channel;				 +	 +	if (tfr_reg & DMA_CHANNEL(chan)) { +		/* +		 *Each DMA command produces 2 interrupts.  Only +		 * complete the command after both interrupts have been +		 * seen. (See sata_dwc_isr()) +		 */ +		hsdevp->dma_interrupt_count++; +		sata_dwc_clear_dmacr(hsdevp, tag); + +		if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE)) { +			dev_err(ap->dev, "DMA not pending eot=0x%08x " +				"err=0x%08x tag=0x%02x pending=%d\n", +				tfr_reg, err_reg, tag, +				hsdevp->dma_pending[tag]); +		} + +		// Do remain jobs after DMA transfer complete +		if ((hsdevp->dma_interrupt_count % 2) == 0) +			sata_dwc_dma_xfer_complete(ap, 1); + +		/* Clear the interrupt */ +		out_le32(&(sata_dma_regs->interrupt_clear.tfr.low), +			  DMA_CHANNEL(chan)); +	} + +	/* Process error interrupt. */ +	// We do not expect error happen +	if (unlikely(err_reg & DMA_CHANNEL(chan))) { +		/* TODO Need error handler ! */ +		dev_err(ap->dev, "error interrupt err_reg=0x%08x\n", +				err_reg); + +		spin_lock_irqsave(ap->lock, flags); +		//if (ata_is_dma(qc->tf.protocol)) { +			/* disable DMAC */ +			dma_dwc_terminate_dma(ap, chan); +		//} +		spin_unlock_irqrestore(ap->lock, flags); + +		/* Clear the interrupt. */ +		out_le32(&(sata_dma_regs->interrupt_clear.error.low), +			  DMA_CHANNEL(chan)); +	} + +	spin_unlock_irqrestore(&host->lock, flags); +	return IRQ_HANDLED; +} + +static irqreturn_t dma_dwc_handler(int irq, void *hsdev_instance) +{ +	volatile u32 tfr_reg, err_reg; +	int chan; + +	tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));	 +	err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low)); + +	for (chan = 0; chan < DMA_NUM_CHANS; chan++) { +		/* Check for end-of-transfer interrupt. */ + +		if (tfr_reg & DMA_CHANNEL(chan)) { +			dma_dwc_interrupt(0, dwc_dev_list[chan]);		 +		} +		else + +		/* Check for error interrupt. */ +		if (err_reg & DMA_CHANNEL(chan)) { +			dma_dwc_interrupt(0, dwc_dev_list[chan]); +		} +	} + +	return IRQ_HANDLED; +} + +static int dma_register_interrupt (struct sata_dwc_device *hsdev) +{ +	int retval = 0; +	int irq = hsdev->irq_dma; +	/*  +	 * FIXME: 2 SATA controllers share the same DMA engine so +	 * currently, they also share same DMA interrupt +	 */ +	if (!dma_intr_registered) { +		printk("%s register irq (%d)\n", __func__, irq); +		retval = request_irq(irq, dma_dwc_handler, IRQF_SHARED, "SATA DMA", hsdev); +		//retval = request_irq(irq, dma_dwc_handler, IRQF_DISABLED, "SATA DMA", NULL); +		if (retval) { +			dev_err(hsdev->dev, "%s: could not get IRQ %d\n", __func__, irq); +			return -ENODEV; +		} +		//dma_intr_registered = 1; +	} +	return retval; +} + +/* + * Function: dma_request_interrupts + * arguments: hsdev + * returns status + * This function registers ISR for a particular DMA channel interrupt + */ +static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq) +{ +	int retval = 0; +	int dma_chan = hsdev->dma_channel; + +	/* Unmask error interrupt */ +	out_le32(&sata_dma_regs->interrupt_mask.error.low, +			 in_le32(&sata_dma_regs->interrupt_mask.error.low) | DMA_ENABLE_CHAN(dma_chan)); + +	/* Unmask end-of-transfer interrupt */ +	out_le32(&sata_dma_regs->interrupt_mask.tfr.low, +			in_le32(&sata_dma_regs->interrupt_mask.tfr.low) | DMA_ENABLE_CHAN(dma_chan)); + +	dwc_dev_vdbg(hsdev->dev, "Current value of interrupt_mask.error=0x%0x\n", in_le32(&sata_dma_regs->interrupt_mask.error.low)); +	dwc_dev_vdbg(hsdev->dev, "Current value of interrupt_mask.tfr=0x%0x\n", in_le32(&sata_dma_regs->interrupt_mask.tfr.low)); +#if 0 +	out_le32(&sata_dma_regs->interrupt_mask.block.low, +			DMA_ENABLE_CHAN(dma_chan)); + +	out_le32(&sata_dma_regs->interrupt_mask.srctran.low, +			DMA_ENABLE_CHAN(dma_chan)); + +	out_le32(&sata_dma_regs->interrupt_mask.dsttran.low, +			DMA_ENABLE_CHAN(dma_chan)); +#endif +	return retval; +} + +/* + * Function: map_sg_to_lli + * arguments: sg: scatter/gather list(sg) + *	      num_elems: no of elements in sg list + *	      dma_lli: LLI table + *	      dest: destination address + *	      read: whether the transfer is read or write + * returns array of AHB DMA Linked List Items + * This function creates a list of LLIs for DMA Xfr and returns the number + * of elements in the DMA linked list. + * + * Note that the Synopsis driver has a comment proposing that better performance + * is possible by only enabling interrupts on the last item in the linked list. + * However, it seems that could be a problem if an error happened on one of the + * first items.  The transfer would halt, but no error interrupt would occur. + * + * Currently this function sets interrupts enabled for each linked list item: + * DMA_CTL_INT_EN. + */ +static int map_sg_to_lli(struct ata_queued_cmd *qc, struct lli *lli, +			 dma_addr_t dma_lli, void __iomem *dmadr_addr) +{ +	struct scatterlist *sg = qc->sg; +	struct device *dwc_dev = qc->ap->dev; +	int num_elems = qc->n_elem; +	int dir = qc->dma_dir; +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(qc->ap); +	 +	int i, idx = 0; +	int fis_len = 0; +	dma_addr_t next_llp; +	int bl; +	unsigned int dma_ts = 0; + +	dwc_port_vdbg(qc->ap, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x " +		"dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, +		(u32)dmadr_addr); + +	bl = get_burst_length_encode(AHB_DMA_BRST_DFLT); + +	for (i = 0; i < num_elems; i++, sg++) { +		u32 addr, offset; +		u32 sg_len, len; + +		addr = (u32) sg_dma_address(sg); +		sg_len = sg_dma_len(sg); + +		dwc_port_vdbg(qc->ap, "%s: elem=%d sg_addr=0x%x sg_len=%d\n", +			__func__, i, addr, sg_len); + +		while (sg_len) { + +			if (unlikely(idx >= SATA_DWC_DMAC_LLI_NUM)) { +				/* The LLI table is not large enough. */ +				dev_err(dwc_dev, "LLI table overrun (idx=%d)\n", +						idx); +				break; +			} +			len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ? +				SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len; + +			offset = addr & 0xffff; +			if ((offset + sg_len) > 0x10000) +				len = 0x10000 - offset; + +			/* +			 * Make sure a LLI block is not created that will span a +			 * 8K max FIS boundary.  If the block spans such a FIS +			 * boundary, there is a chance that a DMA burst will +			 * cross that boundary -- this results in an error in +			 * the host controller. +			 */ +			if (unlikely(fis_len + len > 8192)) { +				dwc_port_vdbg(qc->ap, "SPLITTING: fis_len=%d(0x%x) " +					"len=%d(0x%x)\n", fis_len, fis_len, +					len, len); +				len = 8192 - fis_len; +				fis_len = 0; +			} else { +				fis_len += len; +			} +			if (fis_len == 8192) +				fis_len = 0; + +			/* +			 * Set DMA addresses and lower half of control register +			 * based on direction. +			 */ +			dwc_port_vdbg(qc->ap, "%s: sg_len = %d, len = %d\n", __func__, sg_len, len); + +#if defined(CONFIG_APM821xx) +			 if (dir == DMA_FROM_DEVICE) { +                                lli[idx].dar = cpu_to_le32(addr); +                                lli[idx].sar = cpu_to_le32((u32)dmadr_addr); +				if (hsdevp->hsdev->dma_channel == 0) {/* DMA channel 0 */ +		                        lli[idx].ctl.low = cpu_to_le32( +                                        DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | +                                        DMA_CTL_SMS(1) |	/* Source: Master 2 */ +                                        DMA_CTL_DMS(0) |	/* Dest: Master 1 */ +                                        DMA_CTL_SRC_MSIZE(bl) | +                                        DMA_CTL_DST_MSIZE(bl) | +                                        DMA_CTL_SINC_NOCHANGE | +                                        DMA_CTL_SRC_TRWID(2) | +                                        DMA_CTL_DST_TRWID(2) | +                                        DMA_CTL_INT_EN | +                                        DMA_CTL_LLP_SRCEN | +                                        DMA_CTL_LLP_DSTEN); +				} else if (hsdevp->hsdev->dma_channel == 1) {/* DMA channel 1 */ +					lli[idx].ctl.low = cpu_to_le32( +                                        DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | +                                        DMA_CTL_SMS(2) |	/* Source: Master 3 */ +                                        DMA_CTL_DMS(0) |	/* Dest: Master 1 */ +                                        DMA_CTL_SRC_MSIZE(bl) | +                                        DMA_CTL_DST_MSIZE(bl) | +                                        DMA_CTL_SINC_NOCHANGE | +                                        DMA_CTL_SRC_TRWID(2) | +                                        DMA_CTL_DST_TRWID(2) | +                                        DMA_CTL_INT_EN | +                                        DMA_CTL_LLP_SRCEN | +                                        DMA_CTL_LLP_DSTEN); +				} +                        } else {        /* DMA_TO_DEVICE */ +                                lli[idx].sar = cpu_to_le32(addr); +                                lli[idx].dar = cpu_to_le32((u32)dmadr_addr); +				if (hsdevp->hsdev->dma_channel == 0) {/* DMA channel 0 */ +	                                lli[idx].ctl.low = cpu_to_le32( +                                        DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | +                                        DMA_CTL_SMS(0) | +                                        DMA_CTL_DMS(1) | +                                        DMA_CTL_SRC_MSIZE(bl) | +                                        DMA_CTL_DST_MSIZE(bl) | +                                        DMA_CTL_DINC_NOCHANGE | +                                        DMA_CTL_SRC_TRWID(2) | +                                        DMA_CTL_DST_TRWID(2) | +                                        DMA_CTL_INT_EN | +                                        DMA_CTL_LLP_SRCEN | +                                        DMA_CTL_LLP_DSTEN); +				} else if (hsdevp->hsdev->dma_channel == 1) {/* DMA channel 1 */ +	                                lli[idx].ctl.low = cpu_to_le32( +                                        DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | +                                        DMA_CTL_SMS(0) | +                                        DMA_CTL_DMS(2) | +                                        DMA_CTL_SRC_MSIZE(bl) | +                                        DMA_CTL_DST_MSIZE(bl) | +                                        DMA_CTL_DINC_NOCHANGE | +                                        DMA_CTL_SRC_TRWID(2) | +                                        DMA_CTL_DST_TRWID(2) | +                                        DMA_CTL_INT_EN | +                                        DMA_CTL_LLP_SRCEN | +                                        DMA_CTL_LLP_DSTEN); +				} +                        } +#else +			if (dir == DMA_FROM_DEVICE) { +				lli[idx].dar = cpu_to_le32(addr); +				lli[idx].sar = cpu_to_le32((u32)dmadr_addr); + +				lli[idx].ctl.low = cpu_to_le32( +					DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | +					DMA_CTL_SMS(0) | +					DMA_CTL_DMS(1) | +					DMA_CTL_SRC_MSIZE(bl) | +					DMA_CTL_DST_MSIZE(bl) | +					DMA_CTL_SINC_NOCHANGE | +					DMA_CTL_SRC_TRWID(2) | +					DMA_CTL_DST_TRWID(2) | +					DMA_CTL_INT_EN | +					DMA_CTL_LLP_SRCEN | +					DMA_CTL_LLP_DSTEN); +			} else {	/* DMA_TO_DEVICE */ +				lli[idx].sar = cpu_to_le32(addr); +				lli[idx].dar = cpu_to_le32((u32)dmadr_addr); + +				lli[idx].ctl.low = cpu_to_le32( +					DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | +					DMA_CTL_SMS(1) | +					DMA_CTL_DMS(0) | +					DMA_CTL_SRC_MSIZE(bl) | +					DMA_CTL_DST_MSIZE(bl) | +					DMA_CTL_DINC_NOCHANGE | +					DMA_CTL_SRC_TRWID(2) | +					DMA_CTL_DST_TRWID(2) | +					DMA_CTL_INT_EN | +					DMA_CTL_LLP_SRCEN | +					DMA_CTL_LLP_DSTEN); +			} +#endif +			dwc_port_vdbg(qc->ap, "%s setting ctl.high len: 0x%08x val: " +					"0x%08x\n", __func__, len, +					DMA_CTL_BLK_TS(len / 4)); + +			/* Program the LLI CTL high register */ +			dma_ts = DMA_CTL_BLK_TS(len / 4); +			lli[idx].ctl.high = cpu_to_le32(dma_ts); + +			/* +			 *Program the next pointer.  The next pointer must be +			 * the physical address, not the virtual address. +			 */ +			next_llp = (dma_lli + ((idx + 1) * sizeof(struct lli))); + +			/* The last 2 bits encode the list master select. */ +#if defined(CONFIG_APM821xx) +			next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER1); +#else +			next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2); +#endif + +			lli[idx].llp = cpu_to_le32(next_llp); + +			dwc_port_vdbg(qc->ap, "%s: index %d\n", __func__, idx); +			dwc_port_vdbg(qc->ap, "%s setting ctl.high with val: 0x%08x\n", __func__, lli[idx].ctl.high); +			dwc_port_vdbg(qc->ap, "%s setting ctl.low with val: 0x%08x\n", __func__, lli[idx].ctl.low); +			dwc_port_vdbg(qc->ap, "%s setting lli.dar with val: 0x%08x\n", __func__, lli[idx].dar); +			dwc_port_vdbg(qc->ap, "%s setting lli.sar with val: 0x%08x\n", __func__, lli[idx].sar); +			dwc_port_vdbg(qc->ap, "%s setting next_llp with val: 0x%08x\n", __func__, lli[idx].llp); + +			idx++; +			sg_len -= len; +			addr += len; +		} +	} + +	/* +	 * The last next ptr has to be zero and the last control low register +	 * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source +	 * and destination enable) set back to 0 (disabled.)  This is what tells +	 * the core that this is the last item in the linked list. +	 */ +	if (likely(idx)) { +		lli[idx-1].llp = 0x00000000; +		lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32; + +		/* Flush cache to memory */ +		dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx), +			       DMA_BIDIRECTIONAL); +	} + +	dwc_port_vdbg(qc->ap, "%s: Final index %d\n", __func__, idx-1); +	dwc_port_vdbg(qc->ap, "%s setting ctl.high with val: 0x%08x\n", __func__, lli[idx-1].ctl.high); +	dwc_port_vdbg(qc->ap, "%s setting ctl.low with val: 0x%08x\n", __func__, lli[idx-1].ctl.low); +	dwc_port_vdbg(qc->ap, "%s setting lli.dar with val: 0x%08x\n", __func__, lli[idx-1].dar); +	dwc_port_vdbg(qc->ap, "%s setting lli.sar with val: 0x%08x\n", __func__, lli[idx-1].sar); +	dwc_port_vdbg(qc->ap, "%s setting next_llp with val: 0x%08x\n", __func__, lli[idx-1].llp); + +	return idx; +} + +/* + * Function: dma_dwc_xfer_start + * arguments: Channel number + * Return : None + * Enables the DMA channel + */ +static void dma_dwc_xfer_start(int dma_ch) +{ +	/* Enable the DMA channel */ +	out_le32(&(sata_dma_regs->dma_chan_en.low), +		 in_le32(&(sata_dma_regs->dma_chan_en.low)) | +		 DMA_ENABLE_CHAN(dma_ch)); + +#if defined(CONFIG_SATA_DWC_VDEBUG) +	printk("DMA CFG = 0x%08x\n", in_le32(&(sata_dma_regs->dma_cfg.low))); +	printk("%s: setting sata_dma_regs->dma_chan_en.low with val: 0x%08x\n", +                __func__, in_le32(&(sata_dma_regs->dma_chan_en.low))); +#endif + +   +#if defined(CONFIG_APOLLO3G) +	signal_hdd_led(1 /*blink=yes*/, 2 /* _3G_LED_GREEN */); +#endif + +} + +/* + * Check if the selected DMA channel is currently enabled. + */ +static int dma_dwc_channel_enabled(int ch) +{ +	u32 dma_chan; + +	// Read the DMA channel register +	dma_chan = in_le32(&(sata_dma_regs->dma_chan_en.low)); +	if (dma_chan & DMA_CHANNEL(ch)) +		return 1; + +	return 0; +} + +/* + * Terminate the current DMA transaction + */ +static void dma_dwc_terminate_dma(struct ata_port *ap, int dma_ch) +{ +	int enabled = dma_dwc_channel_enabled(dma_ch); + +	dev_info(ap->dev, "%s terminate DMA on channel=%d enabled=%d\n", +		 __func__, dma_ch, enabled); + +	if (enabled)  { +		// Disable the selected channel +		out_le32(&(sata_dma_regs->dma_chan_en.low), +			 in_le32(&(sata_dma_regs->dma_chan_en.low)) | DMA_DISABLE_CHAN(dma_ch)); + +		// Wait for the channel is disabled +		do { +			enabled = dma_dwc_channel_enabled(dma_ch); +			msleep(10); +		} while (enabled); +	} +} + + +/* + * Setup data and DMA configuration ready for DMA transfer + */ +static int dma_dwc_xfer_setup(struct ata_queued_cmd *qc, +			      struct lli *lli, dma_addr_t dma_lli, +			      void __iomem *addr) +{ +	int dma_ch; +	int num_lli; + +	/* Acquire DMA channel */ +	dma_ch = dma_request_channel(qc->ap); +	if (unlikely(dma_ch == -1)) { +		dev_err(qc->ap->dev, "%s: dma channel unavailable\n", __func__); +		return -EAGAIN; +	} +	dwc_port_vdbg(qc->ap, "%s: Got channel %d\n", __func__, dma_ch); + +	/* Convert SG list to linked list of items (LLIs) for AHB DMA */ +	num_lli = map_sg_to_lli(qc, lli, dma_lli, addr); + +	dwc_port_vdbg(qc->ap, "%s sg: 0x%p, count: %d lli: %p dma_lli: 0x%0xlx addr:" +		" %p lli count: %d\n", __func__, qc->sg, qc->n_elem, lli, +		(u32)dma_lli, addr, num_lli); + +	/* Clear channel interrupts */ +	clear_chan_interrupts(dma_ch); +	 +	/* Program the CFG register. */ +#if defined(CONFIG_APM821xx) +	if (dma_ch == 0) { +		/* Buffer mode enabled, FIFO_MODE=0 */ +		out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high), 0x0000009); +		/* Channel 0 bit[7:5] */ +		out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0x00000020); +	} else if (dma_ch == 1) { +		/* Buffer mode enabled, FIFO_MODE=0 */ +		out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high), 0x0000088d); +		/* Channel 1 bit[7:5] */ +		out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0x00000020); +	} +#else +	out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high), +		 DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ); +	out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0); +#endif + +	/* Program the address of the linked list */ +#if defined(CONFIG_APM821xx) +	out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low), +                 DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER1)); +#else +	out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low), +		 DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2)); +#endif + +	/* Program the CTL register with src enable / dst enable */ +	//out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low), +	//	 DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN); +	out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low), 0x18000000); + +	dwc_port_vdbg(qc->ap, "%s DMA channel %d is ready\n", __func__, dma_ch); +	dwc_port_vdbg(qc->ap, "%s setting cfg.high of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high))); +	dwc_port_vdbg(qc->ap, "%s setting cfg.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low))); +	dwc_port_vdbg(qc->ap, "%s setting llp.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low))); +	dwc_port_vdbg(qc->ap, "%s setting ctl.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low))); + +	return dma_ch; +} + +/* + * Function: dma_dwc_exit + * arguments: None + * returns status + * This function exits the SATA DMA driver + */ +static void dma_dwc_exit(struct sata_dwc_device *hsdev) +{ +	dwc_dev_vdbg(hsdev->dev, "%s:\n", __func__); +	if (sata_dma_regs) +		iounmap(sata_dma_regs); + +	if (hsdev->irq_dma) +		free_irq(hsdev->irq_dma, hsdev); +} + +/* + * Function: dma_dwc_init + * arguments: hsdev + * returns status + * This function initializes the SATA DMA driver + */ +static int dma_dwc_init(struct sata_dwc_device *hsdev) +{ +	int err; +	int irq = hsdev->irq_dma; + +	err = dma_request_interrupts(hsdev, irq); +	if (err) { +		dev_err(hsdev->dev, "%s: dma_request_interrupts returns %d\n", +			__func__, err); +		goto error_out; +	} + +	/* Enabe DMA */ +	out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN); + +	dev_notice(hsdev->dev, "DMA initialized\n"); +	dev_notice(hsdev->dev, "DMA CFG = 0x%08x\n", in_le32(&(sata_dma_regs->dma_cfg.low))); +	dwc_dev_vdbg(hsdev->dev, "SATA DMA registers=0x%p\n", sata_dma_regs); + +	return 0; + +error_out: +	dma_dwc_exit(hsdev); + +	return err; +} + + +static void sata_dwc_dev_config(struct ata_device *adev) +{ +	/* +	 * Does not support NCQ over a port multiplier +	 *  (no FIS-based switching). +	 */ +	if (adev->flags & ATA_DFLAG_NCQ) { +		/* +		 * TODO: debug why enabling NCQ makes the linux crashed  +		 * in hot plug after the first hot unplug action. +		 * --> need to investigate more +		 */ +		adev->flags &= ~ATA_DFLAG_NCQ; +		if (sata_pmp_attached(adev->link->ap)) { +			adev->flags &= ~ATA_DFLAG_NCQ; +			ata_dev_printk(adev, KERN_INFO, +				"NCQ disabled for command-based switching\n"); +		} +	} + +	/* +	 * Since the sata_pmp_error_handler function in libata-pmp  +	 * make FLAG_AN disabled in the first time SATA port is configured. +	 * Asynchronous notification is not configured. +	 * This will enable the AN feature manually. +	 */ +	adev->flags |= ATA_DFLAG_AN; +} + + +static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) +{ +	if (unlikely(scr > SCR_NOTIFICATION)) { +		dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n", +				__func__, scr); +		return -EINVAL; +	} + +	*val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4)); +	dwc_dev_vdbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", +		__func__, link->ap->print_id, scr, *val); + +	return 0; +} + +static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val) +{ +	dwc_dev_vdbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", +		__func__, link->ap->print_id, scr, val); +	if (unlikely(scr > SCR_NOTIFICATION)) { +		dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n", +				__func__, scr); +		return -EINVAL; +	} +	out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val); + +	return 0; +} + +static inline u32 sata_dwc_core_scr_read ( struct ata_port *ap, unsigned int scr) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	return in_le32((void __iomem *)hsdev->scr_base + (scr * 4)); +} + + +static inline void sata_dwc_core_scr_write ( struct ata_port *ap, unsigned int scr, u32 val) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	out_le32((void __iomem *)hsdev->scr_base + (scr * 4), val); +} + +static inline void clear_serror(struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	out_le32( (void __iomem *)hsdev->scr_base + 4, +		in_le32((void __iomem *)hsdev->scr_base + 4)); +} + +static inline void clear_intpr(struct sata_dwc_device *hsdev) +{ +	out_le32(&hsdev->sata_dwc_regs->intpr, +		 in_le32(&hsdev->sata_dwc_regs->intpr)); +} + +static inline void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) +{ +	out_le32(&hsdev->sata_dwc_regs->intpr, bit); +		// in_le32(&hsdev->sata_dwc_regs->intpr)); +} + + +static inline void enable_err_irq(struct sata_dwc_device *hsdev) +{ +	out_le32(&hsdev->sata_dwc_regs->intmr, +		 in_le32(&hsdev->sata_dwc_regs->intmr) | SATA_DWC_INTMR_ERRM); +	out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERR_ERR_BITS); +} + +static inline u32 qcmd_tag_to_mask(u8 tag) +{ +	return 0x00000001 << (tag & 0x1f); +} + + +/* + * Timer to monitor SCR_NOTIFICATION registers on the  + * SATA port + */ +static void sata_dwc_an_chk(unsigned long arg) +{ +	struct ata_port *ap = (void *)arg; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	unsigned long flags; +	int rc = 0x0; +	u32 sntf = 0x0; + +	spin_lock_irqsave(ap->lock, flags); +	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + +	// If some changes on the SCR4, call asynchronous notification +	if ( (rc == 0) & (sntf  != 0)) { +		dwc_port_dbg(ap, "Call assynchronous notification sntf=0x%08x\n", sntf); +		sata_async_notification(ap); +		hsdev->an_timer.expires = jiffies + msecs_to_jiffies(8000); +	} else { +		hsdev->an_timer.expires = jiffies + msecs_to_jiffies(3000); +	} +	add_timer(&hsdev->an_timer); +	spin_unlock_irqrestore(ap->lock, flags); +} + + +/* + *   sata_dwc_pmp_select - Set the PMP field in SControl to the specified port number. + * + *   @port: The value (port number) to set the PMP field to. + * + *   @return: The old value of the PMP field. + */ +static u32 sata_dwc_pmp_select(struct ata_port *ap, u32 port) +{ +	u32 scontrol, old_port; +	if (sata_pmp_supported(ap)) { +		scontrol = sata_dwc_core_scr_read(ap, SCR_CONTROL); +		old_port = SCONTROL_TO_PMP(scontrol); + +		// Select new PMP port +		if ( port != old_port )  { +			scontrol &= ~SCONTROL_PMP_MASK; +			sata_dwc_core_scr_write(ap, SCR_CONTROL, scontrol | PMP_TO_SCONTROL(port)); +			dwc_port_dbg(ap, "%s: old port=%d new port=%d\n", __func__, old_port, port); +		} +		return old_port; +	}  +	else +		return port; +} + +/* + * Get the current PMP port + */ +static inline u32 current_pmp(struct ata_port *ap) +{ +	return SCONTROL_TO_PMP(sata_dwc_core_scr_read(ap, SCR_CONTROL)); +} + + +/*  + * Process when a PMP card is attached in the SATA port. + * Since our SATA port support command base switching only, + * NCQ will not be available. + * We disable the NCQ feature in SATA port. + */ +static void sata_dwc_pmp_attach ( struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + +	dev_info(ap->dev, "Attach SATA port multiplier with %d ports\n", ap->nr_pmp_links); +	// Disable NCQ +	ap->flags &= ~ATA_FLAG_NCQ; + +	// Initialize timer for checking AN +	init_timer(&hsdev->an_timer); +	hsdev->an_timer.expires = jiffies + msecs_to_jiffies(20000); +	hsdev->an_timer.function = sata_dwc_an_chk; +	hsdev->an_timer.data = (unsigned long)(ap); +	add_timer(&hsdev->an_timer); +} + +/* + * Process when PMP card is removed from the SATA port. + * Re-enable NCQ for using by the SATA drive in the future + */ +static void sata_dwc_pmp_detach ( struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + +	dev_info(ap->dev, "Detach SATA port\n"); +	// Re-enable NCQ +	// TODO: remove the below comment out when NCQ problem fixed +	//ap->flags |= ATA_FLAG_NCQ; + +	sata_dwc_pmp_select(ap, 0); + +	// Delete timer since PMP card is detached +	del_timer(&hsdev->an_timer); +} + + + +// Check the link to be ready +int sata_dwc_check_ready ( struct ata_link *link ) { +	u8 status; +	struct ata_port *ap = link->ap; +	status = ioread8(ap->ioaddr.status_addr); +	return ata_check_ready(status); +} + + +/* + * Do soft reset on the current SATA link. + */ +static int sata_dwc_softreset(struct ata_link *link, unsigned int *classes, +				unsigned long deadline) +{ +	int rc; +	struct ata_port *ap = link->ap; +	struct ata_ioports *ioaddr = &ap->ioaddr; +	struct ata_taskfile tf; + +	sata_dwc_pmp_select(link->ap, sata_srst_pmp(link)); + +	/* Issue bus reset */ +	iowrite8(ap->ctl, ioaddr->ctl_addr); +	udelay(20);	/* FIXME: flush */ +	iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); +	udelay(20);	/* FIXME: flush */ +	iowrite8(ap->ctl, ioaddr->ctl_addr); +	ap->last_ctl = ap->ctl; + +	/* Always check readiness of the master device */ +	rc = ata_wait_after_reset(link, deadline, sata_dwc_check_ready); + +	// Classify the ata_port +	*classes = ATA_DEV_NONE; +	/* Verify if SStatus indicates device presence */ +	if (ata_link_online(link)) { +		memset(&tf, 0, sizeof(tf)); +		ata_sff_tf_read(ap, &tf); +		*classes = ata_dev_classify(&tf); +	} + +	if ( *classes == ATA_DEV_PMP) +		dwc_link_dbg(link, "-->found PMP device by sig\n"); + +	clear_serror(link->ap); + +	return rc; +} + + + + +/* + * sata_dwc_hardreset - Do hardreset the SATA controller + */ +static int sata_dwc_hardreset(struct ata_link *link, unsigned int *classes, +			   unsigned long deadline) +{ +	int rc; +	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); +	bool online; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap); + +	dwc_link_dbg(link, "%s\n", __func__); +	sata_dwc_pmp_select(link->ap, sata_srst_pmp(link)); +	dwc_port_vdbg(link->ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr))); + +	// Call standard hard reset +	rc = sata_link_hardreset(link, timing, deadline, &online, NULL); + +	// Reconfigure the port after hard reset +	if ( ata_link_online(link) ) +		sata_dwc_init_port(link->ap); + +	return online ? -EAGAIN : rc; +} + +/* + * Do hard reset on each PMP link + */ +static int sata_dwc_pmp_hardreset(struct ata_link *link, unsigned int *classes, +			   unsigned long deadline) +{ +	int rc = 0; +	sata_dwc_pmp_select(link->ap, sata_srst_pmp(link)); +	rc = sata_std_hardreset(link, classes, deadline); +	return rc; +} + +/* See ahci.c */ +/* + * Process error when the SATAn_INTPR's ERR bit is set + * The processing is based on SCR_ERROR register content + */ +static void sata_dwc_error_intr(struct ata_port *ap, +				struct sata_dwc_device *hsdev, uint intpr) +{ +	struct ata_eh_info *ehi; +	struct ata_link *link; +	struct ata_queued_cmd *active_qc = NULL; +	u32 serror; +	bool freeze = false, abort = false; +	int pmp, ret; +	unsigned int err_mask = 0, action = 0; +#if defined(CONFIG_SATA_DWC_VDEBUG) +	int dma_chan = hsdev->dma_channel; +#endif + +	link = &ap->link; +	ehi = &link->eh_info; + +	/* Record irq stat */ +	ata_ehi_clear_desc(ehi); +	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", intpr); + +	// Record SERROR +	serror = sata_dwc_core_scr_read(ap, SCR_ERROR); +	dwc_port_dbg(ap, "%s serror = 0x%08x\n", __func__, serror); + +	// Clear SERROR and interrupt bit +	clear_serror(ap); +	clear_intpr(hsdev); + +	// Print out for test only +	if ( serror ) { +		dwc_port_info(ap, "Detect errors:"); +		if ( serror & SATA_DWC_SERR_ERRI ) +			printk(" ERRI"); +		if ( serror & SATA_DWC_SERR_ERRM ) +			printk(" ERRM"); +		if ( serror & SATA_DWC_SERR_ERRT ) +			printk(" ERRT"); +		if ( serror & SATA_DWC_SERR_ERRC ) +			printk(" ERRC"); +		if ( serror & SATA_DWC_SERR_ERRP ) +			printk(" ERRP"); +		if ( serror & SATA_DWC_SERR_ERRE ) +			printk(" ERRE"); +		if ( serror & SATA_DWC_SERR_DIAGN ) +			printk(" DIAGN"); +		if ( serror & SATA_DWC_SERR_DIAGI ) +			printk(" DIAGI"); +		if ( serror & SATA_DWC_SERR_DIAGW ) +			printk(" DIAGW"); +		if ( serror & SATA_DWC_SERR_DIAGB ) +			printk(" DIAGB"); +		if ( serror & SATA_DWC_SERR_DIAGT ) +			printk(" DIAGT"); +		if ( serror & SATA_DWC_SERR_DIAGC ) +			printk(" DIAGC"); +		if ( serror & SATA_DWC_SERR_DIAGH ) +			printk(" DIAGH"); +		if ( serror & SATA_DWC_SERR_DIAGL ) +			printk(" DIAGL"); +		if ( serror & SATA_DWC_SERR_DIAGS ) +			printk(" DIAGS"); +		if ( serror & SATA_DWC_SERR_DIAGF ) +			printk(" DIAGF"); +		if ( serror & SATA_DWC_SERR_DIAGX ) +			printk(" DIAGX"); +		if ( serror & SATA_DWC_SERR_DIAGA ) +			printk(" DIAGA"); +		printk("\n"); +	} + +#if defined(CONFIG_SATA_DWC_VDEBUG) +        printk("%s reading cfg.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].cfg.high))); +        printk("%s reading cfg.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].cfg.low))); +        printk("%s reading llp.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].llp.low))); +        printk("%s reading ctl.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].ctl.low))); +        printk("%s reading sar.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].sar.low))); +        printk("%s reading sar.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].sar.high))); +        printk("%s reading dar.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].dar.low))); +        printk("%s reading dar.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].dar.high))); +#endif + +	// Process hotplug for SATA port +	if ( serror & (SATA_DWC_SERR_DIAGX | SATA_DWC_SERR_DIAGW)) { +		dwc_port_info(ap, "Detect hot plug signal\n"); +		ata_ehi_hotplugged(ehi); +		ata_ehi_push_desc(ehi, serror & SATA_DWC_SERR_DIAGN ? "PHY RDY changed" : "device exchanged"); +		freeze = true; +	} + +	// Process PHY internal error / Link sequence (illegal transition) error +	if ( serror & (SATA_DWC_SERR_DIAGI | SATA_DWC_SERR_DIAGL)) { +		ehi->err_mask |= AC_ERR_HSM; +		ehi->action |= ATA_EH_RESET; +		freeze = true; +	} + +	// Process Internal host adapter error +	if ( serror & SATA_DWC_SERR_ERRE ) { +		dev_err(ap->dev, "Detect Internal host adapter error\n"); +		// --> need to review +		ehi->err_mask |= AC_ERR_HOST_BUS; +		ehi->action |= ATA_EH_RESET; +		freeze = true; +	} + +	// Process Protocol Error +	if ( serror & SATA_DWC_SERR_ERRP ) { +		dev_err(ap->dev, "Detect Protocol error\n"); +		ehi->err_mask |= AC_ERR_HSM; +		ehi->action |= ATA_EH_RESET; +		freeze = true; +	} + +	// Process non-recovered persistent communication error +	if ( serror & SATA_DWC_SERR_ERRC ) { +		dev_err(ap->dev, "Detect non-recovered persistent communication error\n"); +		// --> TODO: review processing error +		ehi->err_mask |= AC_ERR_ATA_BUS; +		ehi->action |= ATA_EH_SOFTRESET; +		//ehi->flags |= ATA_EHI_NO_AUTOPSY; +		//freeze = true; +	} + +	// Non-recovered transient data integrity error +	if ( serror & SATA_DWC_SERR_ERRT ) { +		dev_err(ap->dev, "Detect non-recovered transient data integrity error\n"); +		ehi->err_mask |= AC_ERR_ATA_BUS; +		//ehi->err_mask |= AC_ERR_DEV; +		ehi->action |= ATA_EH_SOFTRESET; +		//ehi->flags |= ATA_EHI_NO_AUTOPSY; +	} + +	// Since below errors have been recovered by hardware +	// they don't need any error processing. +	if ( serror & SATA_DWC_SERR_ERRM ) { +		dev_warn(ap->dev, "Detect recovered communication error"); +	} +	if ( serror & SATA_DWC_SERR_ERRI ) { +		dev_warn(ap->dev, "Detect recovered data integrity error"); +	} + +	// If any error occur, process the qc +	if (serror & (SATA_DWC_SERR_ERRT | SATA_DWC_SERR_ERRC)) { +	//if (serror & 0x03f60f0) { +		abort = true; +		/* find out the offending link and qc */ +		if (sata_pmp_attached(ap)) { +			pmp = current_pmp(ap); +			// If we are working on the PMP port +			if ( pmp < ap->nr_pmp_links ) { +				link = &ap->pmp_link[pmp]; +				ehi = &link->eh_info; +				active_qc = ata_qc_from_tag(ap, link->active_tag); +				err_mask |= AC_ERR_DEV; +				ata_ehi_clear_desc(ehi); +				ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); +			} else { +				err_mask |= AC_ERR_HSM; +				action |= ATA_EH_RESET; +				freeze = true; +			} +		 +		} +		// Work on SATA port +		else { +			freeze = true; +			active_qc = ata_qc_from_tag(ap, link->active_tag); +		} + +		if ( active_qc) { +			active_qc->err_mask |= err_mask; +		} else { +			ehi->err_mask = err_mask; +		} +	} + +	if ( freeze | abort ) { +		//sata_dwc_qc_complete(ap, active_qc, 1); +		// Terminate DMA channel if it is currenly in use +		if ( dma_request_channel(ap) != -1 ) { +			dwc_port_dbg(ap, "Terminate DMA channel %d for handling error\n", hsdev->dma_channel); +			dma_dwc_terminate_dma(ap, hsdev->dma_channel); +		} +	} + +	if (freeze) { +		ret = ata_port_freeze(ap); +		ata_port_printk(ap, KERN_INFO, "Freeze port with %d QCs aborted\n", ret); +	} +	else if (abort) { +		if (active_qc) { +			ret = ata_link_abort(active_qc->dev->link); +			ata_link_printk(link, KERN_INFO, "Abort %d QCs\n", ret); +		} else { +			ret = ata_port_abort(ap); +			ata_port_printk(ap, KERN_INFO, "Abort %d QCs on the SATA port\n", ret); +		} +	} +} + + +/* + * Function : sata_dwc_isr + * arguments : irq, void *dev_instance, struct pt_regs *regs + * Return value : irqreturn_t - status of IRQ + * This Interrupt handler called via port ops registered function. + * .irq_handler = sata_dwc_isr + */ +static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) +{ +	struct ata_host *host = (struct ata_host *)dev_instance; +	struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host); +	struct ata_port *ap; +	struct ata_queued_cmd *qc; +	unsigned long flags; +	u8 status, tag; +	int handled, num_processed, port = 0; +	u32 intpr, sactive, sactive2, tag_mask; +	struct sata_dwc_device_port *hsdevp; + +	spin_lock_irqsave(&host->lock, flags); + +	/* Read the interrupt register */ +	intpr = in_le32(&hsdev->sata_dwc_regs->intpr); + +	ap = host->ports[port]; +	hsdevp = HSDEVP_FROM_AP(ap); + +	dwc_port_dbg(ap,"%s\n",__func__); +	if ( intpr != 0x80000080) +		dwc_port_dbg(ap, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr, ap->link.active_tag); +	//dwc_port_dbg(ap, "%s: INTMR=0x%08x, ERRMR=0x%08x\n", __func__, in_le32(&hsdev->sata_dwc_regs->intmr), in_le32(&hsdev->sata_dwc_regs->errmr)); + +	/* Check for error interrupt */ +	if (intpr & SATA_DWC_INTPR_ERR) { +		sata_dwc_error_intr(ap, hsdev, intpr); +		handled = 1; +#if defined(CONFIG_APOLLO3G) +		signal_hdd_led(0 /*off blink*/, 1 /*red color*/); +#endif +		goto done_irqrestore; +	} + +	/* Check for DMA SETUP FIS (FP DMA) interrupt */ +	if (intpr & SATA_DWC_INTPR_NEWFP) { +		dwc_port_dbg(ap, "%s: NEWFP INTERRUPT in HSDEV with DMA channel %d\n", __func__, hsdev->dma_channel); +		clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP); + +		tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr)); +		dwc_dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); +		if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PENDING) +			dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag); + +		hsdevp->sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag); + +		qc = ata_qc_from_tag(ap, tag); +		/* +		 * Start FP DMA for NCQ command.  At this point the tag is the +		 * active tag.  It is the tag that matches the command about to +		 * be completed. +		 */ +		qc->ap->link.active_tag = tag; +		sata_dwc_bmdma_start_by_tag(qc, tag); +		qc->ap->hsm_task_state = HSM_ST_LAST; + +		handled = 1; +		goto done_irqrestore; +	} + +	sactive = sata_dwc_core_scr_read(ap, SCR_ACTIVE); +	tag_mask = (hsdevp->sata_dwc_sactive_issued | sactive) ^ sactive; + +	/* If no sactive issued and tag_mask is zero then this is not NCQ */ +	if (hsdevp->sata_dwc_sactive_issued == 0 && tag_mask == 0) { +		if (ap->link.active_tag == ATA_TAG_POISON) +			tag = 0; +		else +			tag = ap->link.active_tag; +		qc = ata_qc_from_tag(ap, tag); + +		/* DEV interrupt w/ no active qc? */ +		if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { +			dev_err(ap->dev, "%s intr with no active qc qc=%p\n", +				__func__, qc); +			ap->ops->sff_check_status(ap); +			handled = 1; +			goto done_irqrestore; +		} + +		status = ap->ops->sff_check_status(ap); + +		qc->ap->link.active_tag = tag; +		hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; + +		if (status & ATA_ERR) { +			dwc_dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status); +			sata_dwc_qc_complete(ap, qc, 1); +			handled = 1; +			goto done_irqrestore; +		} + +		dwc_dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n", +			__func__, prot_2_txt(qc->tf.protocol)); +drv_still_busy: +		if (ata_is_dma(qc->tf.protocol)) { +			int dma_flag = hsdevp->dma_pending[tag]; +			/* +			 * Each DMA transaction produces 2 interrupts.  The DMAC +			 * transfer complete interrupt and the SATA controller +			 * operation done interrupt. The command should be +			 * completed only after both interrupts are seen. +			 */ +			hsdevp->dma_interrupt_count++; +			if (unlikely(dma_flag == SATA_DWC_DMA_PENDING_NONE)) { +				dev_err(ap->dev, "%s: DMA not pending " +					"intpr=0x%08x status=0x%08x pend=%d\n", +					__func__, intpr, status, dma_flag); +			} + +			if ((hsdevp->dma_interrupt_count % 2) == 0) +				sata_dwc_dma_xfer_complete(ap, 1); +		} else if (ata_is_pio(qc->tf.protocol)) { +			ata_sff_hsm_move(ap, qc, status, 0); +			handled = 1; +			goto done_irqrestore; +		} else { +			if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) +				goto drv_still_busy; +		} + +		handled = 1; +		goto done_irqrestore; +	} + +	/* +	 * This is a NCQ command.  At this point we need to figure out for which +	 * tags we have gotten a completion interrupt.  One interrupt may serve +	 * as completion for more than one operation when commands are queued +	 * (NCQ).  We need to process each completed command. +	 */ + +process_cmd:  /* process completed commands */ +	sactive = sata_dwc_core_scr_read(ap, SCR_ACTIVE); +	tag_mask = (hsdevp->sata_dwc_sactive_issued | sactive) ^ sactive; + +	if (sactive != 0 || hsdevp->sata_dwc_sactive_issued > 1 || tag_mask > 1) { +		dwc_dev_dbg(ap->dev, "%s NCQ: sactive=0x%08x  sactive_issued=0x%08x" +			" tag_mask=0x%08x\n", __func__, sactive, +			hsdevp->sata_dwc_sactive_issued, tag_mask); +	} + +	if (unlikely((tag_mask | hsdevp->sata_dwc_sactive_issued) != hsdevp->sata_dwc_sactive_issued)) { +		dev_warn(ap->dev, "Bad tag mask?  sactive=0x%08x " +			 "sata_dwc_sactive_issued=0x%08x  tag_mask=0x%08x\n", +			 sactive, hsdevp->sata_dwc_sactive_issued, tag_mask); +	} + +	/* read just to clear ... not bad if currently still busy */ +	status = ap->ops->sff_check_status(ap); +	dwc_dev_dbg(ap->dev, "%s ATA status register=0x%x, tag_mask=0x%x\n", __func__, status, tag_mask); + +	tag = 0; +	num_processed = 0; +	while (tag_mask) { +		num_processed++; +		while (!(tag_mask & 0x00000001)) { +			tag++; +			tag_mask <<= 1; +		} +		tag_mask &= (~0x00000001); +		qc = ata_qc_from_tag(ap, tag); + +		/* To be picked up by completion functions */ +		qc->ap->link.active_tag = tag; +		hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; + +		/* Let libata/scsi layers handle error */ +		if (unlikely(status & ATA_ERR)) { +			dwc_dev_vdbg(ap->dev, "%s ATA_ERR (0x%x)\n", +					 __func__, status); + +			sata_dwc_qc_complete(ap, qc, 1); +			handled = 1; +			goto done_irqrestore; +		} + +		/* Process completed command */ +		dwc_dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__, +			prot_2_txt(qc->tf.protocol)); +		if (ata_is_dma(qc->tf.protocol)) { +			hsdevp->dma_interrupt_count++; +			if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) +				dev_warn(ap->dev, +					"%s: DMA not pending?\n", __func__); +			if ((hsdevp->dma_interrupt_count % 2) == 0) +				sata_dwc_dma_xfer_complete(ap, 1); +		} else { +			if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) +				goto still_busy; +		} +		continue; + +still_busy: +		ap->stats.idle_irq++; +		dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n", +				ap->print_id); +	} /* while tag_mask */ + +	/* +	 * Check to see if any commands completed while we were processing our +	 * initial set of completed commands (reading of status clears +	 * interrupts, so we might miss a completed command interrupt if one +	 * came in while we were processing: +	 * we read status as part of processing a completed command). +	 */ +	sactive2 = sata_dwc_core_scr_read(ap, SCR_ACTIVE); +	if (sactive2 != sactive) { +		dwc_dev_dbg(ap->dev, "More finished - sactive=0x%x sactive2=0x%x\n", +			sactive, sactive2); +		goto process_cmd; +	} +	handled = 1; + +done_irqrestore: +	spin_unlock_irqrestore(&host->lock, flags); +#if defined(CONFIG_APOLLO3G) +	signal_hdd_led(0 /*off blink*/, -1 /* no color */); +#endif +	return IRQ_RETVAL(handled); +} + + +/* + * Clear DMA Control Register after completing transferring data + * using AHB DMA. + */ +static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp); + +	if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) { +		// Clear receive channel enable bit +		out_le32(&(hsdev->sata_dwc_regs->dmacr), +			 SATA_DWC_DMACR_RX_CLEAR( +				 in_le32(&(hsdev->sata_dwc_regs->dmacr)))); +	} else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) { +		// Clear transmit channel enable bit +		out_le32(&(hsdev->sata_dwc_regs->dmacr), +			 SATA_DWC_DMACR_TX_CLEAR( +				 in_le32(&(hsdev->sata_dwc_regs->dmacr)))); +	} else { +		/* +		 * This should not happen, it indicates the driver is out of +		 * sync.  If it does happen, clear dmacr anyway. +		 */ +		dev_err(hsdev->dev, "%s DMA protocol RX and TX DMA not pending " +			"tag=0x%02x pending=%d dmacr: 0x%08x\n", +			__func__, tag, hsdevp->dma_pending[tag], +			in_le32(&(hsdev->sata_dwc_regs->dmacr))); + +		// Clear all transmit and receive bit, but TXMOD bit is set to 1 +		out_le32(&(hsdev->sata_dwc_regs->dmacr), +				SATA_DWC_DMACR_TXRXCH_CLEAR); +	} +} + +/* + * + */ +static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status) +{ +	struct ata_queued_cmd *qc; +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	u8 tag = 0; + +	tag = ap->link.active_tag; +	qc = ata_qc_from_tag(ap, tag); + +#ifdef DEBUG_NCQ +	if (tag > 0) { +		dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s " +			 "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command, +			 dir_2_txt(qc->dma_dir), prot_2_txt(qc->tf.protocol), +			 in_le32(&(hsdev->sata_dwc_regs->dmacr))); +	} +#endif + +	if (ata_is_dma(qc->tf.protocol)) { +		// DMA out of sync error +		if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE)) { +			dev_err(ap->dev, "%s DMA protocol RX and TX DMA not " +				"pending dmacr: 0x%08x\n", __func__, +				in_le32(&(hsdev->sata_dwc_regs->dmacr))); +		} + +		hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE; +		sata_dwc_qc_complete(ap, qc, check_status); +		ap->link.active_tag = ATA_TAG_POISON; +	} else { +		sata_dwc_qc_complete(ap, qc, check_status); +	} +} + +/* + * + */ +static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, +				u32 check_status) +{ +	u8 status = 0; +	int i = 0; +	u32 mask = 0x0; +	u8 tag = qc->tag; +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	u32 serror; +	int dma_ch; + +	dwc_dev_vdbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status); + +	if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX)) +		dev_err(ap->dev, "TX DMA PENDINGING\n"); +	else if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX)) +		dev_err(ap->dev, "RX DMA PENDINGING\n"); + +	if (check_status) { +		i = 0; +		do { +			/* check main status, clearing INTRQ */ +			status = ap->ops->sff_check_status(ap); +			if (status & ATA_BUSY) { +				dwc_dev_vdbg(ap->dev, "STATUS BUSY (0x%02x) [%d]\n", +						status, i); +			} +			if (++i > 10) +				break; +		} while (status & ATA_BUSY); + +		status = ap->ops->sff_check_status(ap); +		if (unlikely(status & ATA_BUSY)) +			dev_err(ap->dev, "QC complete cmd=0x%02x STATUS BUSY " +				"(0x%02x) [%d]\n", qc->tf.command, status, i); + + +		// Check error ==> need to process error here +		serror = sata_dwc_core_scr_read(ap, SCR_ERROR); +		if (unlikely(serror & SATA_DWC_SERR_ERR_BITS)) +		{ +			dev_err(ap->dev, "****** SERROR=0x%08x ******\n", serror); +			ap->link.eh_context.i.action |= ATA_EH_RESET; +			if (ata_is_dma(qc->tf.protocol)) { +				dma_ch = hsdevp->dma_chan[tag]; +				dma_dwc_terminate_dma(ap, dma_ch); +			} else { +				dma_ch = hsdevp->dma_chan[0]; +				dma_dwc_terminate_dma(ap, dma_ch); +			} +		} +	} +	dwc_dev_vdbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u: " +		"protocol=%d\n", qc->tf.command, status, ap->print_id, +		qc->tf.protocol); + +	/* clear active bit */ +	mask = (~(qcmd_tag_to_mask(tag))); +	hsdevp->sata_dwc_sactive_queued = hsdevp->sata_dwc_sactive_queued & mask; +	hsdevp->sata_dwc_sactive_issued = hsdevp->sata_dwc_sactive_issued & mask; +	dwc_port_vdbg(ap, "%s - sata_dwc_sactive_queued=0x%08x, sata_dwc_sactive_issued=0x%08x\n",__func__, hsdevp->sata_dwc_sactive_queued, hsdevp->sata_dwc_sactive_issued); +	dwc_port_vdbg(ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr))); + +	/* Complete taskfile transaction (does not read SCR registers) */ +	ata_qc_complete(qc); + +	return 0; +} + +/* + * Clear interrupt and error flags in DMA status register. + */ +void sata_dwc_irq_clear (struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	dwc_port_dbg(ap,"%s\n",__func__); + +	// Clear DMA interrupts +	clear_chan_interrupts(hsdev->dma_channel); +	//sata_dma_regs +	//out_le32(&hsdev->sata_dwc_regs->intmr, +	//	 in_le32(&hsdev->sata_dwc_regs->intmr) & ~SATA_DWC_INTMR_ERRM); +	//out_le32(&hsdev->sata_dwc_regs->errmr, 0x0); +	//sata_dwc_check_status(ap); +} + +/* + * Turn on IRQ + */ +void sata_dwc_irq_on(struct ata_port *ap) +{ +	struct ata_ioports *ioaddr = &ap->ioaddr; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	u8 tmp; + +	dwc_port_dbg(ap,"%s\n",__func__); +	ap->ctl &= ~ATA_NIEN; +	ap->last_ctl = ap->ctl; + +	if (ioaddr->ctl_addr) +		iowrite8(ap->ctl, ioaddr->ctl_addr); +	tmp = ata_wait_idle(ap); + +	ap->ops->sff_irq_clear(ap); +	enable_err_irq(hsdev); +} + + +/* + * This function enables the interrupts in IMR and unmasks them in ERRMR + *  + */ +static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev) +{ +	// Enable interrupts +	out_le32(&hsdev->sata_dwc_regs->intmr, +		 SATA_DWC_INTMR_ERRM | +		 SATA_DWC_INTMR_NEWFPM | +		 SATA_DWC_INTMR_PMABRTM | +		 SATA_DWC_INTMR_DMATM); + +	/* +	 * Unmask the error bits that should trigger an error interrupt by +	 * setting the error mask register. +	 */ +	out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERR_ERR_BITS); + +	dwc_dev_dbg(hsdev->dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n", __func__, +		in_le32(&hsdev->sata_dwc_regs->intmr), +		in_le32(&hsdev->sata_dwc_regs->errmr)); +} + +/*  + * Configure DMA and interrupts on SATA port. This should be called after + * hardreset is executed on the SATA port. + */ +static void sata_dwc_init_port ( struct ata_port *ap ) { +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + +	// Configure DMA +	if (ap->port_no == 0)  { +		dwc_dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n", +				__func__); + +		// Clear all transmit/receive bits +		out_le32(&hsdev->sata_dwc_regs->dmacr, +			 SATA_DWC_DMACR_TXRXCH_CLEAR); + +		dwc_dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__); +		out_le32(&hsdev->sata_dwc_regs->dbtsr, +			 (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | +			  SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); +	} + +	// Enable interrupts +	sata_dwc_enable_interrupts(hsdev); +} + + +/* + * Setup SATA ioport with corresponding register addresses + */ +static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base) +{ +	port->cmd_addr = (void *)base + 0x00; +	port->data_addr = (void *)base + 0x00; + +	port->error_addr = (void *)base + 0x04; +	port->feature_addr = (void *)base + 0x04; + +	port->nsect_addr = (void *)base + 0x08; + +	port->lbal_addr = (void *)base + 0x0c; +	port->lbam_addr = (void *)base + 0x10; +	port->lbah_addr = (void *)base + 0x14; + +	port->device_addr = (void *)base + 0x18; +	port->command_addr = (void *)base + 0x1c; +	port->status_addr = (void *)base + 0x1c; + +	port->altstatus_addr = (void *)base + 0x20; +	port->ctl_addr = (void *)base + 0x20; +} + + +/* + * Function : sata_dwc_port_start + * arguments : struct ata_ioports *port + * Return value : returns 0 if success, error code otherwise + * This function allocates the scatter gather LLI table for AHB DMA + */ +static int sata_dwc_port_start(struct ata_port *ap) +{ +	int err = 0; +	struct sata_dwc_device *hsdev; +	struct sata_dwc_device_port *hsdevp = NULL; +	struct device *pdev; +	u32 sstatus; +	int i; + +	hsdev = HSDEV_FROM_AP(ap); + +	dwc_dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no); + +	hsdev->host = ap->host; +	pdev = ap->host->dev; +	if (!pdev) { +		dev_err(ap->dev, "%s: no ap->host->dev\n", __func__); +		err = -ENODEV; +		goto cleanup_exit; +	} + +	/* Allocate Port Struct */ +	hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL); +	if (!hsdevp) { +		dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__); +		err = -ENOMEM; +		goto cleanup_exit; +	} +	hsdevp->hsdev = hsdev; + +	for (i = 0; i < SATA_DWC_QCMD_MAX; i++) +		hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + +	ap->bmdma_prd = 0;	/* set these so libata doesn't use them */ +	ap->bmdma_prd_dma = 0; + +	/* +	 * DMA - Assign scatter gather LLI table. We can't use the libata +	 * version since it's PRD is IDE PCI specific. +	 */ +	for (i = 0; i < SATA_DWC_QCMD_MAX; i++) { +		hsdevp->llit[i] = dma_alloc_coherent(pdev, +						     SATA_DWC_DMAC_LLI_TBL_SZ, +						     &(hsdevp->llit_dma[i]), +						     GFP_ATOMIC); +		if (!hsdevp->llit[i]) { +			dev_err(ap->dev, "%s: dma_alloc_coherent failed size " +				"0x%x\n", __func__, SATA_DWC_DMAC_LLI_TBL_SZ); +			err = -ENOMEM; +			goto cleanup_exit; +		} +	} + +	if (ap->port_no == 0)  { +		dwc_dev_vdbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n", +				__func__); + +		out_le32(&hsdev->sata_dwc_regs->dmacr, +			 SATA_DWC_DMACR_TXRXCH_CLEAR); + +		dwc_dev_vdbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__); +		out_le32(&hsdev->sata_dwc_regs->dbtsr, +			 (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | +			  SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); +		 ata_port_printk(ap, KERN_INFO, "%s: setting burst size in DBTSR: 0x%08x\n",  +			__func__, in_le32(&hsdev->sata_dwc_regs->dbtsr)); +	} + +	/* Clear any error bits before libata starts issuing commands */ +	clear_serror(ap); + +	ap->private_data = hsdevp; + +	/* Are we in Gen I or II */ +	sstatus = sata_dwc_core_scr_read(ap, SCR_STATUS); +	switch (SATA_DWC_SCR0_SPD_GET(sstatus)) { +	case 0x0: +		dev_info(ap->dev, "**** No neg speed (nothing attached?) \n"); +		break; +	case 0x1: +		dev_info(ap->dev, "**** GEN I speed rate negotiated \n"); +		break; +	case 0x2: +		dev_info(ap->dev, "**** GEN II speed rate negotiated \n"); +		break; +	} + +cleanup_exit: +	if (err) { +		kfree(hsdevp); +		sata_dwc_port_stop(ap); +		dwc_dev_vdbg(ap->dev, "%s: fail\n", __func__); +	} else { +		dwc_dev_vdbg(ap->dev, "%s: done\n", __func__); +	} + +	return err; +} + + +static void sata_dwc_port_stop(struct ata_port *ap) +{ +	int i; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + +	dwc_port_dbg(ap, "%s: stop port\n", __func__); + +	if (hsdevp && hsdev) { +		/* deallocate LLI table */ +		for (i = 0; i < SATA_DWC_QCMD_MAX; i++) { +			dma_free_coherent(ap->host->dev, +					  SATA_DWC_DMAC_LLI_TBL_SZ, +					  hsdevp->llit[i], hsdevp->llit_dma[i]); +		} + +		kfree(hsdevp); +	} +	ap->private_data = NULL; +} + +/* + * Since the SATA DWC is master only. The dev select operation will  + * be removed. + */ +void sata_dwc_dev_select(struct ata_port *ap, unsigned int device) +{ +	// Do nothing +	ndelay(100); +} + +/* + * Function : sata_dwc_exec_command_by_tag + * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued + * Return value : None + * This function keeps track of individual command tag ids and calls + * ata_exec_command in libata + */ +static void sata_dwc_exec_command_by_tag(struct ata_port *ap, +					 struct ata_taskfile *tf, +					 u8 tag, u32 cmd_issued) +{ +	unsigned long flags; +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + +	dwc_dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d, ap->link->tag=0x%08x\n", __func__, tf->command, +		ata_cmd_2_txt(tf), tag, ap->link.active_tag); + +	spin_lock_irqsave(&ap->host->lock, flags); +	hsdevp->cmd_issued[tag] = cmd_issued; +	spin_unlock_irqrestore(&ap->host->lock, flags); + +	/* +	 * Clear SError before executing a new command. +	 * +	 * TODO if we read a PM's registers now, we will throw away the task +	 * file values loaded into the shadow registers for this command. +	 * +	 * sata_dwc_scr_write and read can not be used here. Clearing the PM +	 * managed SError register for the disk needs to be done before the +	 * task file is loaded. +	 */ +	clear_serror(ap); +	ata_sff_exec_command(ap, tf); +} + +static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ +	sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag, +				     SATA_DWC_CMD_ISSUED_PENDING); +} + +static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc) +{ +	u8 tag = qc->tag; + +	dwc_port_dbg(qc->ap, "%s\n", __func__); +	if (ata_is_ncq(qc->tf.protocol)) { +		dwc_dev_vdbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n", +			__func__, qc->ap->link.sactive, tag); +	} else { +		tag = 0; +	} + +	sata_dwc_bmdma_setup_by_tag(qc, tag); +} + +static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ +	volatile int start_dma; +	u32 reg, dma_chan; +	struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc); +	struct ata_port *ap = qc->ap; +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); +	int dir = qc->dma_dir; +	dma_chan = hsdevp->dma_chan[tag]; + +	/* Used for ata_bmdma_start(qc) -- we are not BMDMA compatible */ + +	if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) { +		start_dma = 1; +		if (dir == DMA_TO_DEVICE) +			hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX; +		else +			hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX; +	} else { +		dev_err(ap->dev, "%s: Command not pending cmd_issued=%d " +			"(tag=%d) - DMA NOT started\n", __func__, +			hsdevp->cmd_issued[tag], tag); +		start_dma = 0; +	} + +	dwc_dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s " +			"start_dma? %x\n", __func__, qc, tag, qc->tf.command, +			dir_2_txt(qc->dma_dir), start_dma); +	sata_dwc_tf_dump(hsdev->dev, &(qc->tf)); + +	// Start DMA transfer +	if (start_dma) { +		reg = sata_dwc_core_scr_read(ap, SCR_ERROR); +		if (unlikely(reg & SATA_DWC_SERR_ERR_BITS)) { +			dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n", +				__func__, reg); +			//sata_async_notification(ap); +			//return; +		} + +		// Set DMA control registers +		if (dir == DMA_TO_DEVICE) +			out_le32(&hsdev->sata_dwc_regs->dmacr, +					SATA_DWC_DMACR_TXCHEN); +		else +			out_le32(&hsdev->sata_dwc_regs->dmacr, +					SATA_DWC_DMACR_RXCHEN); + +		dwc_dev_vdbg(ap->dev, "%s: setting DMACR: 0x%08x\n", __func__, in_le32(&hsdev->sata_dwc_regs->dmacr)); +		/* Enable AHB DMA transfer on the specified channel */ +		dma_dwc_xfer_start(dma_chan); +	} +} + + +static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc) +{ +	u8 tag = qc->tag; + +	if (ata_is_ncq(qc->tf.protocol)) { +		dwc_dev_vdbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n", +			__func__, qc->ap->link.sactive, tag); +	} else { +		tag = 0; +	} + +	dwc_port_dbg(qc->ap, "%s, tag=0x%08x\n", __func__, tag); +	sata_dwc_bmdma_start_by_tag(qc, tag); +} + +/* + * Function : sata_dwc_qc_prep_by_tag + * arguments : ata_queued_cmd *qc, u8 tag + * Return value : None + * qc_prep for a particular queued command based on tag + */ +static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ +	struct ata_port *ap = qc->ap; +	int dma_chan; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); +	int dir; + +	// DMA direction +	dir = qc->dma_dir; + +	if ((dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO)) +		return; + +	dwc_dev_vdbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n", +		__func__, ap->port_no, dir_2_txt(dir), qc->n_elem); + +	// Setup DMA for transfer +	dma_chan = dma_dwc_xfer_setup(qc, hsdevp->llit[tag], +			hsdevp->llit_dma[tag], +			(void *__iomem)(&hsdev->sata_dwc_regs->dmadr)); + +	if (unlikely(dma_chan < 0)) { +		dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n", +			__func__, dma_chan); +		return; +	} + +	hsdevp->dma_chan[tag] = dma_chan; +} + + + +/** + *	ata_sff_exec_command - issue ATA command to host controller + *	@ap: port to which command is being issued + *	@tf: ATA taskfile register set + * + *	Issues ATA command, with proper synchronization with interrupt + *	handler / other threads. + * + *	LOCKING: + *	spin_lock_irqsave(host lock) + */ +void sata_dwc_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) +{ +	iowrite8(tf->command, ap->ioaddr.command_addr); +	/*	If we have an mmio device with no ctl and no altstatus +	 *	method this will fail. No such devices are known to exist. +	 */ +	if (ap->ioaddr.altstatus_addr) +		ioread8(ap->ioaddr.altstatus_addr); +	ndelay(400); +} + +/** + *	sata_dwc_tf_to_host - issue ATA taskfile to host controller + *	@ap: port to which command is being issued + *	@tf: ATA taskfile register set + * + *	Issues ATA taskfile register set to ATA host controller, + *	with proper synchronization with interrupt handler and + *	other threads. + * + *	LOCKING: + *	spin_lock_irqsave(host lock) + */ +static inline void sata_dwc_tf_to_host(struct ata_port *ap, +				  const struct ata_taskfile *tf) +{ +	dwc_port_dbg(ap,"%s\n",__func__); +	ap->ops->sff_tf_load(ap, tf); +	sata_dwc_exec_command(ap, tf); +} + + +/* + * Process command queue issue + */ +static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) +{ +	struct ata_port *ap = qc->ap; +	int ret = 0; +	struct ata_eh_info *ehi; +	u32 scontrol, sstatus; +	scontrol = sata_dwc_core_scr_read(ap, SCR_CONTROL); + +	ehi = &ap->link.eh_info; +	/* +	 * Fix the problem when PMP card is unplugged from the SATA port. +	 * QC is still issued but no device present. Ignore the current QC. +	 * and pass error to error handler +	 */ +	sstatus = sata_dwc_core_scr_read(ap, SCR_STATUS); +	if ( sstatus == 0x0) { +		ata_port_printk(ap, KERN_INFO, "Detect connection lost while commands are executing --> ignore current command\n"); +		ata_ehi_hotplugged(ehi); +		ap->link.eh_context.i.action |= ATA_EH_RESET; +		return ret; +	} + +	// Set PMP field in the SCONTROL register +	if ( sata_pmp_attached(ap) ) +		sata_dwc_pmp_select(ap, qc->dev->link->pmp); + +#ifdef DEBUG_NCQ +	if (qc->tag > 0 || ap->link.sactive > 1) { +		dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d prot=%s" +			" ap active_tag=0x%08x ap sactive=0x%08x\n", +			__func__, ap->print_id, qc->tf.command, +			ata_cmd_2_txt(&qc->tf), qc->tag, +			prot_2_txt(qc->tf.protocol), ap->link.active_tag, +			ap->link.sactive); +	} +#endif + +	// Process NCQ +	if (ata_is_ncq(qc->tf.protocol)) { +		dwc_link_dbg(qc->dev->link, "%s --> process NCQ , ap->link.active_tag=0x%08x, active_tag=0%08x\n", __func__, ap->link.active_tag, qc->tag); +		ap->link.active_tag = qc->tag; +		ap->ops->sff_tf_load(ap, &qc->tf); +		sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag, +					     SATA_DWC_CMD_ISSUED_PENDING); +	} else { +		dwc_link_dbg(qc->dev->link, "%s --> non NCQ process, ap->link.active_tag=%d, active_tag=0%08x\n", __func__, ap->link.active_tag, qc->tag); +		// Sync ata_port with qc->tag +		ap->link.active_tag = qc->tag; +		ret = ata_bmdma_qc_issue(qc); +	} + +	return ret; +} + +#if 0 +/* + * Function : sata_dwc_eng_timeout + * arguments : ata_port *ap + * Return value : None + * error handler for DMA time out + * ata_eng_timeout(ap) -- this does bmdma stuff which can not be done by this + * driver. SEE ALSO ata_qc_timeout(ap) + */ +static void sata_dwc_eng_timeout(struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); +	struct ata_queued_cmd *qc; +	u8  tag; +	uint mask = 0x0; +	unsigned long flags; +	u32 serror, intpr, dma_ch; + +	tag = ap->link.active_tag; +	dma_ch = hsdevp->dma_chan[tag]; +	qc = ata_qc_from_tag(ap, tag); + +	dev_err(ap->dev, "%s: id=%d active_tag=%d qc=%p dma_chan=%d\n", +		__func__, ap->print_id, tag, qc, dma_ch); + +	intpr = in_le32(&hsdev->sata_dwc_regs->intpr); +	serror = sata_dwc_core_scr_read(ap, SCR_ERROR); + +	dev_err(ap->dev, "intpr=0x%08x serror=0x%08x\n", intpr, serror); + +	/* If there are no error bits set, can we just pass this on to eh? */ +	if (!(serror & SATA_DWC_SERR_ERR_BITS) && +	    !(intpr & SATA_DWC_INTPR_ERR)) { + +		spin_lock_irqsave(&ap->host->lock, flags); +		if (dma_dwc_channel_enabled(dma_ch)) +			dma_dwc_terminate_dma(ap, dma_ch); + +		hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE; + +		/* clear active bit */ +		mask = (~(qcmd_tag_to_mask(tag))); +		hsdevp->sata_dwc_sactive_queued = hsdevp->sata_dwc_sactive_queued & mask; +		hsdevp->sata_dwc_sactive_issued = hsdevp->sata_dwc_sactive_issued & mask; + +		spin_unlock_irqrestore(&ap->host->lock, flags); +	} else { +		/* This is wrong, what really needs to be done is a reset. */ + +		spin_lock_irqsave(ap->lock, flags); + +		if (ata_is_dma(qc->tf.protocol)) { +			/* disable DMAC */ +			dma_dwc_terminate_dma(ap, dma_ch); +		} + +		spin_unlock_irqrestore(ap->lock, flags); +	} +	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); +	if (qc->flags & ATA_QCFLAG_ACTIVE) { +		qc->err_mask |= AC_ERR_TIMEOUT; +		/* +		 * test-only: The original code (AMCC: 2.6.19) called +		 * ata_eng_timeout(ap) here. This function is not available +		 * anymore. So what to do now? +		 */ +	} +} +#endif +/* + * Function : sata_dwc_qc_prep + * arguments : ata_queued_cmd *qc + * Return value : None + * qc_prep for a particular queued command + */ +static void sata_dwc_qc_prep(struct ata_queued_cmd *qc) +{ +	u32 sactive; +	u8 tag = qc->tag; + +	 if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO)) +                return; + +#ifdef DEBUG_NCQ +	if (qc->tag > 0) { +		dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n", +			 __func__, qc->tag, qc->ap->link.active_tag); +	} +#endif + +	if (qc->tf.protocol == ATA_PROT_NCQ) { +		sactive = sata_dwc_core_scr_read(qc->ap, SCR_ACTIVE); +		sactive |= (0x00000001 << tag); +		sata_dwc_core_scr_write(qc->ap, SCR_ACTIVE, sactive); +		dwc_dev_vdbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x " +			"sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive, +			sactive); +	} else { +		tag = 0; +	} + +	sata_dwc_qc_prep_by_tag(qc, tag);	 +} + + + +static void sata_dwc_post_internal_cmd(struct ata_queued_cmd *qc) +{ +	if (qc->flags & ATA_QCFLAG_FAILED) +		ata_eh_freeze_port(qc->ap); +} + +static void sata_dwc_error_handler(struct ata_port *ap) +{ +	u32 serror; +	u32 intmr, errmr; +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + +	serror = sata_dwc_core_scr_read(ap, SCR_ERROR); +	intmr = in_le32(&hsdev->sata_dwc_regs->intmr); +	errmr = in_le32(&hsdev->sata_dwc_regs->errmr); + +	//sata_dwc_dma_xfer_complete(ap,1); +	dwc_port_dbg(ap, "%s: SERROR=0x%08x, INTMR=0x%08x, ERRMR=0x%08x\n", __func__, serror, intmr, errmr); + +	dwc_port_vdbg(ap, "%s - sata_dwc_sactive_queued=0x%08x, sata_dwc_sactive_issued=0x%08x\n",__func__, hsdevp->sata_dwc_sactive_queued, hsdevp->sata_dwc_sactive_issued); +	dwc_port_vdbg(ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr))); +	dwc_port_vdbg(ap, "qc_active=0x%08x, qc_allocated=0x%08x, active_tag=%d\n", ap->qc_active, ap->qc_allocated, ap->link.active_tag); + +	sata_pmp_error_handler(ap); +} + +/* + * sata_dwc_check_status - Get value of the Status Register + * @ap: Port to check + * + * Output content of the status register (CDR7) + */ +u8 sata_dwc_check_status(struct ata_port *ap) +{ +	return ioread8(ap->ioaddr.status_addr); +} + + +/* + * Freeze the port by clear interrupt + * @ap: Port to freeze + */ +void sata_dwc_freeze(struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); +	dwc_port_dbg(ap, "call %s ...\n",__func__); +	// turn IRQ off +	clear_intpr(hsdev); +	clear_serror(ap); +	out_le32(&hsdev->sata_dwc_regs->intmr, 0x0); +} + +/* + * Thaw the port by turning IRQ on + */ +void sata_dwc_thaw(struct ata_port *ap) +{ +	struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + +	dwc_port_dbg(ap, "call %s ...\n",__func__); +	// Clear IRQ +	clear_intpr(hsdev); +	// Turn IRQ back on +	sata_dwc_enable_interrupts(hsdev); +} + + +/* + * scsi mid-layer and libata interface structures + */ +static struct scsi_host_template sata_dwc_sht = { +	ATA_NCQ_SHT(DRV_NAME), +	/* +	 * test-only: Currently this driver doesn't handle NCQ +	 * correctly. We enable NCQ but set the queue depth to a +	 * max of 1. This will get fixed in in a future release. +	 */ +//        .sg_tablesize           = LIBATA_MAX_PRD, +	.can_queue 		= ATA_DEF_QUEUE,	/* ATA_MAX_QUEUE */ +	.dma_boundary 		= ATA_DMA_BOUNDARY, +}; + + +static struct ata_port_operations sata_dwc_ops = { +	.inherits		= &sata_pmp_port_ops, +	.dev_config		= sata_dwc_dev_config, +	 +	.error_handler	= sata_dwc_error_handler, +	.softreset		= sata_dwc_softreset, +	.hardreset		= sata_dwc_hardreset, +	.pmp_softreset	= sata_dwc_softreset, +	.pmp_hardreset	= sata_dwc_pmp_hardreset, + +	.qc_defer		= sata_pmp_qc_defer_cmd_switch, +	.qc_prep		= sata_dwc_qc_prep, +	.qc_issue		= sata_dwc_qc_issue, +	.qc_fill_rtf	= ata_sff_qc_fill_rtf, + +	.scr_read		= sata_dwc_scr_read, +	.scr_write		= sata_dwc_scr_write, + +	.port_start		= sata_dwc_port_start, +	.port_stop		= sata_dwc_port_stop, + +	.bmdma_setup	= sata_dwc_bmdma_setup, +	.bmdma_start	= sata_dwc_bmdma_start, +	// Reuse some SFF functions +	.sff_check_status	= sata_dwc_check_status, +	.sff_tf_read	= ata_sff_tf_read, +	.sff_data_xfer	= ata_sff_data_xfer, +	.sff_tf_load	= ata_sff_tf_load, +	.sff_dev_select	= sata_dwc_dev_select, +	.sff_exec_command	= sata_dwc_exec_command, + +	.sff_irq_on		= sata_dwc_irq_on, +/*	.sff_irq_clear	= sata_dwc_irq_clear, +	.freeze			= sata_dwc_freeze, +	.thaw			= sata_dwc_thaw, +	.sff_irq_on		= ata_sff_irq_on, +	*/ +	.sff_irq_clear	= ata_bmdma_irq_clear, +	.freeze			= ata_sff_freeze, +	.thaw			= ata_sff_thaw, +	.pmp_attach		= sata_dwc_pmp_attach, +	.pmp_detach		= sata_dwc_pmp_detach, +	.post_internal_cmd	= sata_dwc_post_internal_cmd, + +	/* test-only: really needed? */ +	//.eng_timeout		= sata_dwc_eng_timeout, +}; + +static const struct ata_port_info sata_dwc_port_info[] = { +	{ +		/* +		 * test-only: Currently this driver doesn't handle NCQ +		 * correctly. So we disable NCQ here for now. To enable +		 * it ATA_FLAG_NCQ needs to be added to the flags below. +		 */ +		.flags		= ATA_FLAG_SATA | +				  ATA_FLAG_NCQ | +				  ATA_FLAG_PMP | ATA_FLAG_AN,  +		.pio_mask	= ATA_PIO4,	/* pio 0-4 */  +		.udma_mask	= ATA_UDMA6, +		.port_ops	= &sata_dwc_ops, +	}, +}; + +static int sata_dwc_probe(struct platform_device *ofdev) +{ +	struct sata_dwc_device *hsdev; +	u32 idr, versionr; +	char *ver = (char *)&versionr; +	u8 *base = NULL; +	int err = 0; +	int irq; +	struct ata_host *host; +	struct ata_port_info pi = sata_dwc_port_info[0]; +	const struct ata_port_info *ppi[] = { &pi, NULL }; +	struct device_node *np = ofdev->dev.of_node; +	const unsigned int *dma_channel; +	/* +	 * Check if device is enabled +	 */ +	if (!of_device_is_available(np)) { +		printk(KERN_INFO "%s: Port disabled via device-tree\n",  +			np->full_name); +		return 0; +	} + +	/* Allocate DWC SATA device */ +	hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); +	if (hsdev == NULL) { +		dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); +		err = -ENOMEM; +		goto error; +	} + + +	// Identify SATA DMA channel used for the current SATA device +	dma_channel = of_get_property(np, "dma-channel", NULL); +	if ( dma_channel ) { +		dev_notice(&ofdev->dev, "Gettting DMA channel %d\n", *dma_channel); +		hsdev->dma_channel = *dma_channel; +	} else +		hsdev->dma_channel = 0; + +	/* Ioremap SATA registers */ +	base = of_iomap(np, 0); +	if (!base) { +		dev_err(&ofdev->dev, "ioremap failed for SATA register address\n"); +		err = -ENODEV; +		goto error_kmalloc; +	} +	hsdev->reg_base = base; +	dwc_dev_vdbg(&ofdev->dev, "ioremap done for SATA register address\n"); + +	/* Synopsys DWC SATA specific Registers */ +	hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + +	/* Allocate and fill host */ +	host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); +	if (!host) { +		dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n"); +		err = -ENOMEM; +		goto error_iomap; +	} + +	host->private_data = hsdev; + +	/* Setup port */ +	host->ports[0]->ioaddr.cmd_addr = base; +	host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; +	hsdev->scr_base = (u8 *)(base + SATA_DWC_SCR_OFFSET); +	sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base); + +	/* Read the ID and Version Registers */ +	idr = in_le32(&hsdev->sata_dwc_regs->idr); +	versionr = in_le32(&hsdev->sata_dwc_regs->versionr); +	dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n", +		   idr, ver[0], ver[1], ver[2]); + +	/* Get SATA DMA interrupt number */ +	irq = irq_of_parse_and_map(np, 1); +	if (irq == NO_IRQ) { +		dev_err(&ofdev->dev, "no SATA DMA irq\n"); +		err = -ENODEV; +		goto error_out; +	} + +	/* Get physical SATA DMA register base address */ +	if (!sata_dma_regs) { +	sata_dma_regs = of_iomap(np, 1); +		if (!sata_dma_regs) { +			dev_err(&ofdev->dev, "ioremap failed for AHBDMA register address\n"); +			err = -ENODEV; +			goto error_out; +		} +	} +	/* Save dev for later use in dev_xxx() routines */ +	hsdev->dev = &ofdev->dev; + +	/* Init glovbal dev list */ +	dwc_dev_list[hsdev->dma_channel] = hsdev; + +	/* Initialize AHB DMAC */ +	hsdev->irq_dma = irq; +	dma_dwc_init(hsdev); +	dma_register_interrupt(hsdev); + + +	/* Enable SATA Interrupts */ +	sata_dwc_enable_interrupts(hsdev); + +	/* Get SATA interrupt number */ +	irq = irq_of_parse_and_map(np, 0); +	if (irq == NO_IRQ) { +		dev_err(&ofdev->dev, "no SATA irq\n"); +		err = -ENODEV; +		goto error_out; +	} + +	/* +	 * Now, register with libATA core, this will also initiate the +	 * device discovery process, invoking our port_start() handler & +	 * error_handler() to execute a dummy Softreset EH session +	 */ +	ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); + +	dev_set_drvdata(&ofdev->dev, host); + +	/* Everything is fine */ +	return 0; + +error_out: +	/* Free SATA DMA resources */ +	dma_dwc_exit(hsdev); + +error_iomap: +	iounmap(base); +error_kmalloc: +	kfree(hsdev); +error: +	return err; +} + +static int sata_dwc_remove(struct platform_device *ofdev) +{ +	struct device *dev = &ofdev->dev; +	struct ata_host *host = dev_get_drvdata(dev); +	struct sata_dwc_device *hsdev = host->private_data; + +	ata_host_detach(host); + +	dev_set_drvdata(dev, NULL); + +	/* Free SATA DMA resources */ +	dma_dwc_exit(hsdev); + +	iounmap(hsdev->reg_base); +	kfree(hsdev); +	kfree(host); + +	dwc_dev_vdbg(&ofdev->dev, "done\n"); + +	return 0; +} + +static const struct of_device_id sata_dwc_match[] = { +	{ .compatible = "amcc,sata-460ex", }, +	{ .compatible = "amcc,sata-apm82181", }, +	{} +}; +MODULE_DEVICE_TABLE(of, sata_dwc_match); + +static struct platform_driver sata_dwc_driver = { +	.driver = { +		.name = DRV_NAME, +		.owner = THIS_MODULE, +		.of_match_table = sata_dwc_match, +	}, +	.probe = sata_dwc_probe, +	.remove = sata_dwc_remove, +}; + +module_platform_driver(sata_dwc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>"); +MODULE_DESCRIPTION("DesignWare Cores SATA controller driver"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 851bd3f43ac..616a6d2ac20 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -24,6 +24,8 @@  #include <scsi/scsi_cmnd.h>  #include <linux/libata.h>  #include <asm/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  static unsigned int intr_coalescing_count; @@ -772,20 +774,6 @@ static int sata_fsl_port_start(struct ata_port *ap)  	VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));  	VPRINTK("CHBA  = 0x%x\n", ioread32(hcr_base + CHBA)); -#ifdef CONFIG_MPC8315_DS -	/* -	 * Workaround for 8315DS board 3gbps link-up issue, -	 * currently limit SATA port to GEN1 speed -	 */ -	sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); -	temp &= ~(0xF << 4); -	temp |= (0x1 << 4); -	sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp); - -	sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); -	dev_warn(dev, "scr_control, speed limited to %x\n", temp); -#endif -  	return 0;  } @@ -1586,7 +1574,7 @@ static int sata_fsl_remove(struct platform_device *ofdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sata_fsl_suspend(struct platform_device *op, pm_message_t state)  {  	struct ata_host *host = platform_get_drvdata(op); @@ -1642,7 +1630,7 @@ static struct platform_driver fsl_sata_driver = {  	},  	.probe		= sata_fsl_probe,  	.remove		= sata_fsl_remove, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= sata_fsl_suspend,  	.resume		= sata_fsl_resume,  #endif diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 7f5e5d96327..65965cf5af0 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> @@ -29,7 +28,6 @@  #include <linux/of_address.h>  #include <linux/platform_device.h>  #include <linux/libata.h> -#include <linux/ahci_platform.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/export.h> @@ -143,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; @@ -343,13 +341,11 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr)  {  	struct device_node *sata_node = dev->of_node;  	int phy_count = 0, phy, port = 0, i; -	void __iomem *cphy_base[CPHY_PHY_COUNT]; -	struct device_node *phy_nodes[CPHY_PHY_COUNT]; -	u32 tx_atten[CPHY_PORT_COUNT]; +	void __iomem *cphy_base[CPHY_PHY_COUNT] = {}; +	struct device_node *phy_nodes[CPHY_PHY_COUNT] = {}; +	u32 tx_atten[CPHY_PORT_COUNT] = {};  	memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT); -	memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT); -	memset(tx_atten, 0xff, CPHY_PORT_COUNT);  	do {  		u32 tmp; @@ -406,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; @@ -434,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_inic162x.c b/drivers/ata/sata_inic162x.c index 5c54d957370..069827826b2 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -785,7 +785,7 @@ static int init_controller(void __iomem *mmio_base, u16 hctl)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int inic_pci_device_resume(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -898,7 +898,7 @@ static const struct pci_device_id inic_pci_tbl[] = {  static struct pci_driver inic_pci_driver = {  	.name 		= DRV_NAME,  	.id_table	= inic_pci_tbl, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend	= ata_pci_device_suspend,  	.resume		= inic_pci_device_resume,  #endif diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 56be3181989..391cfda1e83 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -60,6 +60,7 @@  #include <linux/dma-mapping.h>  #include <linux/device.h>  #include <linux/clk.h> +#include <linux/phy/phy.h>  #include <linux/platform_device.h>  #include <linux/ata_platform.h>  #include <linux/mbus.h> @@ -304,6 +305,7 @@ enum {  	MV5_LTMODE		= 0x30,  	MV5_PHY_CTL		= 0x0C,  	SATA_IFCFG		= 0x050, +	LP_PHY_CTL		= 0x058,  	MV_M2_PREAMP_MASK	= 0x7e0, @@ -431,6 +433,7 @@ enum {  	MV_HP_CUT_THROUGH	= (1 << 10),	/* can use EDMA cut-through */  	MV_HP_FLAG_SOC		= (1 << 11),	/* SystemOnChip, no PCI */  	MV_HP_QUIRK_LED_BLINK_EN = (1 << 12),	/* is led blinking enabled? */ +	MV_HP_FIX_LP_PHY_CTL	= (1 << 13),	/* fix speed in LP_PHY_CTL ? */  	/* Port private flags (pp_flags) */  	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */ @@ -563,6 +566,12 @@ struct mv_host_priv {  	struct clk		*clk;  	struct clk              **port_clks;  	/* +	 * Some devices have a SATA PHY which can be enabled/disabled +	 * in order to save power. These are optional: if the platform +	 * devices does not have any phy, they won't be used. +	 */ +	struct phy		**port_phys; +	/*  	 * These consistent DMA memory pools give us guaranteed  	 * alignment for hardware-accessed data structures,  	 * and less memory waste in accomplishing the alignment. @@ -1358,6 +1367,7 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)  	if (ofs != 0xffffffffU) {  		void __iomem *addr = mv_ap_base(link->ap) + ofs; +		struct mv_host_priv *hpriv = link->ap->host->private_data;  		if (sc_reg_in == SCR_CONTROL) {  			/*  			 * Workaround for 88SX60x1 FEr SATA#26: @@ -1374,6 +1384,18 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)  			 */  			if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1)  				val |= 0xf000; + +			if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) { +				void __iomem *lp_phy_addr = +					mv_ap_base(link->ap) + LP_PHY_CTL; +				/* +				 * Set PHY speed according to SControl speed. +				 */ +				if ((val & 0xf0) == 0x10) +					writelfl(0x7, lp_phy_addr); +				else +					writelfl(0x227, lp_phy_addr); +			}  		}  		writelfl(val, addr);  		return 0; @@ -4076,8 +4098,12 @@ static int mv_platform_probe(struct platform_device *pdev)  					GFP_KERNEL);  	if (!hpriv->port_clks)  		return -ENOMEM; +	hpriv->port_phys = devm_kzalloc(&pdev->dev, +					sizeof(struct phy *) * n_ports, +					GFP_KERNEL); +	if (!hpriv->port_phys) +		return -ENOMEM;  	host->private_data = hpriv; -	hpriv->n_ports = n_ports;  	hpriv->board_idx = chip_soc;  	host->iomap = NULL; @@ -4097,8 +4123,26 @@ static int mv_platform_probe(struct platform_device *pdev)  		hpriv->port_clks[port] = clk_get(&pdev->dev, port_number);  		if (!IS_ERR(hpriv->port_clks[port]))  			clk_prepare_enable(hpriv->port_clks[port]); + +		sprintf(port_number, "port%d", port); +		hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev, +							       port_number); +		if (IS_ERR(hpriv->port_phys[port])) { +			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); + +			/* 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.  	 */ @@ -4110,6 +4154,15 @@ static int mv_platform_probe(struct platform_device *pdev)  	if (rc)  		goto err; +	/* +	 * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be +	 * updated in the LP_PHY_CTL register. +	 */ +	if (pdev->dev.of_node && +		of_device_is_compatible(pdev->dev.of_node, +					"marvell,armada-370-sata")) +		hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL; +  	/* initialize adapter */  	rc = mv_init_host(host);  	if (rc) @@ -4127,11 +4180,13 @@ 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]);  		} +		if (hpriv->port_phys[port]) +			phy_power_off(hpriv->port_phys[port]);  	}  	return rc; @@ -4161,11 +4216,13 @@ static int mv_platform_remove(struct platform_device *pdev)  			clk_disable_unprepare(hpriv->port_clks[port]);  			clk_put(hpriv->port_clks[port]);  		} +		if (hpriv->port_phys[port]) +			phy_power_off(hpriv->port_phys[port]);  	}  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state)  {  	struct ata_host *host = platform_get_drvdata(pdev); @@ -4209,6 +4266,7 @@ static int mv_platform_resume(struct platform_device *pdev)  #ifdef CONFIG_OF  static struct of_device_id mv_sata_dt_ids[] = { +	{ .compatible = "marvell,armada-370-sata", },  	{ .compatible = "marvell,orion-sata", },  	{},  }; @@ -4231,7 +4289,7 @@ static struct platform_driver mv_platform_driver = {  #ifdef CONFIG_PCI  static int mv_pci_init_one(struct pci_dev *pdev,  			   const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int mv_pci_device_resume(struct pci_dev *pdev);  #endif @@ -4241,7 +4299,7 @@ static struct pci_driver mv_pci_driver = {  	.id_table		= mv_pci_tbl,  	.probe			= mv_pci_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= mv_pci_device_resume,  #endif @@ -4399,7 +4457,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,  				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int mv_pci_device_resume(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index d74def823d3..cdf99fac139 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> @@ -296,7 +295,7 @@ struct nv_swncq_port_priv {  #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & (1 << (19 + (12 * (PORT)))))  static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int nv_pci_device_resume(struct pci_dev *pdev);  #endif  static void nv_ck804_host_stop(struct ata_host *host); @@ -380,7 +379,7 @@ static struct pci_driver nv_pci_driver = {  	.name			= DRV_NAME,  	.id_table		= nv_pci_tbl,  	.probe			= nv_init_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= nv_pci_device_resume,  #endif @@ -2432,7 +2431,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	return ata_pci_sff_activate_host(host, ipriv->irq_handler, ipriv->sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int nv_pci_device_resume(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 97f4acb54ad..3638887476f 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 3b0dd57984e..9a6bd4cd29a 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_rcar.c b/drivers/ata/sata_rcar.c index c2d95e9fb97..61eb6d77dac 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -15,6 +15,7 @@  #include <linux/module.h>  #include <linux/ata.h>  #include <linux/libata.h> +#include <linux/of_device.h>  #include <linux/platform_device.h>  #include <linux/clk.h>  #include <linux/err.h> @@ -123,12 +124,37 @@  #define SATA_RCAR_DMA_BOUNDARY		0x1FFFFFFEUL +/* Gen2 Physical Layer Control Registers */ +#define RCAR_GEN2_PHY_CTL1_REG		0x1704 +#define RCAR_GEN2_PHY_CTL1		0x34180002 +#define RCAR_GEN2_PHY_CTL1_SS		0xC180	/* Spread Spectrum */ + +#define RCAR_GEN2_PHY_CTL2_REG		0x170C +#define RCAR_GEN2_PHY_CTL2		0x00002303 + +#define RCAR_GEN2_PHY_CTL3_REG		0x171C +#define RCAR_GEN2_PHY_CTL3		0x000B0194 + +#define RCAR_GEN2_PHY_CTL4_REG		0x1724 +#define RCAR_GEN2_PHY_CTL4		0x00030994 + +#define RCAR_GEN2_PHY_CTL5_REG		0x1740 +#define RCAR_GEN2_PHY_CTL5		0x03004001 +#define RCAR_GEN2_PHY_CTL5_DC		BIT(1)	/* DC connection */ +#define RCAR_GEN2_PHY_CTL5_TR		BIT(2)	/* Termination Resistor */ + +enum sata_rcar_type { +	RCAR_GEN1_SATA, +	RCAR_GEN2_SATA, +}; +  struct sata_rcar_priv {  	void __iomem *base;  	struct clk *clk; +	enum sata_rcar_type type;  }; -static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv) +static void sata_rcar_gen1_phy_preinit(struct sata_rcar_priv *priv)  {  	void __iomem *base = priv->base; @@ -141,8 +167,8 @@ static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)  	iowrite32(0, base + SATAPHYRESET_REG);  } -static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val, -				int group) +static void sata_rcar_gen1_phy_write(struct sata_rcar_priv *priv, u16 reg, +				     u32 val, int group)  {  	void __iomem *base = priv->base;  	int timeout; @@ -170,6 +196,29 @@ static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,  	iowrite32(0, base + SATAPHYADDR_REG);  } +static void sata_rcar_gen1_phy_init(struct sata_rcar_priv *priv) +{ +	sata_rcar_gen1_phy_preinit(priv); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1); +	sata_rcar_gen1_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0); +} + +static void sata_rcar_gen2_phy_init(struct sata_rcar_priv *priv) +{ +	void __iomem *base = priv->base; + +	iowrite32(RCAR_GEN2_PHY_CTL1, base + RCAR_GEN2_PHY_CTL1_REG); +	iowrite32(RCAR_GEN2_PHY_CTL2, base + RCAR_GEN2_PHY_CTL2_REG); +	iowrite32(RCAR_GEN2_PHY_CTL3, base + RCAR_GEN2_PHY_CTL3_REG); +	iowrite32(RCAR_GEN2_PHY_CTL4, base + RCAR_GEN2_PHY_CTL4_REG); +	iowrite32(RCAR_GEN2_PHY_CTL5 | RCAR_GEN2_PHY_CTL5_DC | +		  RCAR_GEN2_PHY_CTL5_TR, base + RCAR_GEN2_PHY_CTL5_REG); +} +  static void sata_rcar_freeze(struct ata_port *ap)  {  	struct sata_rcar_priv *priv = ap->host->private_data; @@ -738,13 +787,17 @@ static void sata_rcar_init_controller(struct ata_host *host)  	u32 val;  	/* reset and setup phy */ -	sata_rcar_phy_initialize(priv); -	sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0); -	sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1); -	sata_rcar_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0); -	sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0); -	sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1); -	sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0); +	switch (priv->type) { +	case RCAR_GEN1_SATA: +		sata_rcar_gen1_phy_init(priv); +		break; +	case RCAR_GEN2_SATA: +		sata_rcar_gen2_phy_init(priv); +		break; +	default: +		dev_warn(host->dev, "SATA phy is not initialized\n"); +		break; +	}  	/* SATA-IP reset state */  	val = ioread32(base + ATAPI_CONTROL1_REG); @@ -770,8 +823,40 @@ static void sata_rcar_init_controller(struct ata_host *host)  	iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);  } +static struct of_device_id sata_rcar_match[] = { +	{ +		/* Deprecated by "renesas,sata-r8a7779" */ +		.compatible = "renesas,rcar-sata", +		.data = (void *)RCAR_GEN1_SATA, +	}, +	{ +		.compatible = "renesas,sata-r8a7779", +		.data = (void *)RCAR_GEN1_SATA, +	}, +	{ +		.compatible = "renesas,sata-r8a7790", +		.data = (void *)RCAR_GEN2_SATA +	}, +	{ +		.compatible = "renesas,sata-r8a7791", +		.data = (void *)RCAR_GEN2_SATA +	}, +	{ }, +}; +MODULE_DEVICE_TABLE(of, sata_rcar_match); + +static const struct platform_device_id sata_rcar_id_table[] = { +	{ "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */ +	{ "sata-r8a7779", RCAR_GEN1_SATA }, +	{ "sata-r8a7790", RCAR_GEN2_SATA }, +	{ "sata-r8a7791", RCAR_GEN2_SATA }, +	{ }, +}; +MODULE_DEVICE_TABLE(platform, sata_rcar_id_table); +  static int sata_rcar_probe(struct platform_device *pdev)  { +	const struct of_device_id *of_id;  	struct ata_host *host;  	struct sata_rcar_priv *priv;  	struct resource *mem; @@ -787,12 +872,18 @@ static int sata_rcar_probe(struct platform_device *pdev)  	if (!priv)  		return -ENOMEM; +	of_id = of_match_device(sata_rcar_match, &pdev->dev); +	if (of_id) +		priv->type = (enum sata_rcar_type)of_id->data; +	else +		priv->type = platform_get_device_id(pdev)->driver_data; +  	priv->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(priv->clk)) {  		dev_err(&pdev->dev, "failed to get access to sata clock\n");  		return PTR_ERR(priv->clk);  	} -	clk_enable(priv->clk); +	clk_prepare_enable(priv->clk);  	host = ata_host_alloc(&pdev->dev, 1);  	if (!host) { @@ -822,7 +913,7 @@ static int sata_rcar_probe(struct platform_device *pdev)  		return 0;  cleanup: -	clk_disable(priv->clk); +	clk_disable_unprepare(priv->clk);  	return ret;  } @@ -841,12 +932,12 @@ static int sata_rcar_remove(struct platform_device *pdev)  	iowrite32(0, base + SATAINTSTAT_REG);  	iowrite32(0x7ff, base + SATAINTMASK_REG); -	clk_disable(priv->clk); +	clk_disable_unprepare(priv->clk);  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sata_rcar_suspend(struct device *dev)  {  	struct ata_host *host = dev_get_drvdata(dev); @@ -861,7 +952,7 @@ static int sata_rcar_suspend(struct device *dev)  		/* mask */  		iowrite32(0x7ff, base + SATAINTMASK_REG); -		clk_disable(priv->clk); +		clk_disable_unprepare(priv->clk);  	}  	return ret; @@ -873,7 +964,7 @@ static int sata_rcar_resume(struct device *dev)  	struct sata_rcar_priv *priv = host->private_data;  	void __iomem *base = priv->base; -	clk_enable(priv->clk); +	clk_prepare_enable(priv->clk);  	/* ack and mask */  	iowrite32(0, base + SATAINTSTAT_REG); @@ -892,20 +983,15 @@ static const struct dev_pm_ops sata_rcar_pm_ops = {  };  #endif -static struct of_device_id sata_rcar_match[] = { -	{ .compatible = "renesas,rcar-sata", }, -	{}, -}; -MODULE_DEVICE_TABLE(of, sata_rcar_match); -  static struct platform_driver sata_rcar_driver = {  	.probe		= sata_rcar_probe,  	.remove		= sata_rcar_remove, +	.id_table	= sata_rcar_id_table,  	.driver = {  		.name		= DRV_NAME,  		.owner		= THIS_MODULE,  		.of_match_table	= sata_rcar_match, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  		.pm		= &sata_rcar_pm_ops,  #endif  	}, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index d67fc351343..40b76b2d18c 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> @@ -113,7 +112,7 @@ enum {  };  static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sil_pci_device_resume(struct pci_dev *pdev);  #endif  static void sil_dev_config(struct ata_device *dev); @@ -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 },  	{ }  }; @@ -166,7 +166,7 @@ static struct pci_driver sil_pci_driver = {  	.id_table		= sil_pci_tbl,  	.probe			= sil_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= sil_pci_device_resume,  #endif @@ -802,7 +802,7 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  				 &sil_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sil_pci_device_resume(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index aa1051ba6d1..0534890f118 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -353,8 +353,10 @@ static void sil24_error_handler(struct ata_port *ap);  static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);  static int sil24_port_start(struct ata_port *ap);  static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sil24_pci_device_resume(struct pci_dev *pdev); +#endif +#ifdef CONFIG_PM  static int sil24_port_resume(struct ata_port *ap);  #endif @@ -375,7 +377,7 @@ static struct pci_driver sil24_pci_driver = {  	.id_table		= sil24_pci_tbl,  	.probe			= sil24_init_one,  	.remove			= ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= sil24_pci_device_resume,  #endif @@ -1350,7 +1352,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  				 &sil24_sht);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sil24_pci_device_resume(struct pci_dev *pdev)  {  	struct ata_host *host = pci_get_drvdata(pdev); @@ -1370,7 +1372,9 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)  	return 0;  } +#endif +#ifdef CONFIG_PM  static int sil24_port_resume(struct ata_port *ap)  {  	sil24_config_pmp(ap, ap->nr_pmp_links); diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index fe3ca0989b1..d1637ac40a7 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> @@ -83,6 +82,10 @@ static struct pci_driver sis_pci_driver = {  	.id_table		= sis_pci_tbl,  	.probe			= sis_init_one,  	.remove			= ata_pci_remove_one, +#ifdef CONFIG_PM_SLEEP +	.suspend		= ata_pci_device_suspend, +	.resume			= ata_pci_device_resume, +#endif  };  static struct scsi_host_template sis_sht = { diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index dc4f70179e7..c630fa81262 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 9947010afc0..39b5de60a1f 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 6d648911887..08f98c3ed5c 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 87f056e54a9..47bf89464ce 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> @@ -104,7 +103,7 @@ static struct pci_driver svia_pci_driver = {  	.name			= DRV_NAME,  	.id_table		= svia_pci_tbl,  	.probe			= svia_init_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend		= ata_pci_device_suspend,  	.resume			= ata_pci_device_resume,  #endif diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 44f304b3de6..29e847aac34 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>  | 
