mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 13:34:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			223 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 9b10bc9f84fc221fcef9ddca92972af9b442f49d Mon Sep 17 00:00:00 2001
 | |
| From: Hans de Goede <hdegoede@redhat.com>
 | |
| Date: Mon, 2 Dec 2013 16:13:32 +0100
 | |
| Subject: [PATCH] libahci: Allow drivers to override start_engine
 | |
| 
 | |
| Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
 | |
| special register to be poked before starting the DMA engine.
 | |
| 
 | |
| This register gets reset on an ahci_stop_engine call, so there is no other
 | |
| place then ahci_start_engine where this poking can be done.
 | |
| 
 | |
| This commit allows drivers to override ahci_start_engine behavior for use by
 | |
| the Allwinner AHCI driver (and potentially other drivers in the future).
 | |
| 
 | |
| Signed-off-by: Hans de Goede <hdegoede@redhat.com>
 | |
| ---
 | |
|  drivers/ata/ahci.c          |  6 ++++--
 | |
|  drivers/ata/ahci.h          |  6 ++++++
 | |
|  drivers/ata/libahci.c       | 26 +++++++++++++++++++-------
 | |
|  drivers/ata/sata_highbank.c |  3 ++-
 | |
|  4 files changed, 31 insertions(+), 10 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
 | |
| index dc2756f..eda68b4 100644
 | |
| --- a/drivers/ata/ahci.c
 | |
| +++ b/drivers/ata/ahci.c
 | |
| @@ -564,6 +564,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  				 unsigned long deadline)
 | |
|  {
 | |
|  	struct ata_port *ap = link->ap;
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	bool online;
 | |
|  	int rc;
 | |
|  
 | |
| @@ -574,7 +575,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
 | |
|  				 deadline, &online, NULL);
 | |
|  
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  
 | |
|  	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 | |
|  
 | |
| @@ -589,6 +590,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  {
 | |
|  	struct ata_port *ap = link->ap;
 | |
|  	struct ahci_port_priv *pp = ap->private_data;
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 | |
|  	struct ata_taskfile tf;
 | |
|  	bool online;
 | |
| @@ -604,7 +606,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
 | |
| diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
 | |
| index 2289efd..64d1a99d 100644
 | |
| --- a/drivers/ata/ahci.h
 | |
| +++ b/drivers/ata/ahci.h
 | |
| @@ -323,6 +323,12 @@ struct ahci_host_priv {
 | |
|  	u32			em_msg_type;	/* EM message type */
 | |
|  	struct clk		*clk;		/* Only for platforms supporting clk */
 | |
|  	void			*plat_data;	/* Other platform data */
 | |
| +	/*
 | |
| +	 * Optional ahci_start_engine override, if not set this gets set to the
 | |
| +	 * default ahci_start_engine during ahci_save_initial_config, this can
 | |
| +	 * be overridden anytime before the host is activated.
 | |
| +	 */
 | |
| +	void			(*start_engine)(struct ata_port *ap);
 | |
|  };
 | |
|  
 | |
|  extern int ahci_ignore_sss;
 | |
| diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
 | |
| index 36605ab..f839bb3 100644
 | |
| --- a/drivers/ata/libahci.c
 | |
| +++ b/drivers/ata/libahci.c
 | |
| @@ -394,6 +394,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
 | |
|   *
 | |
|   *	If inconsistent, config values are fixed up by this function.
 | |
|   *
 | |
| + *	If it is not set already this function sets hpriv->start_engine to
 | |
| + *	ahci_start_engine.
 | |
| + *
 | |
|   *	LOCKING:
 | |
|   *	None.
 | |
|   */
 | |
| @@ -500,6 +503,9 @@ void ahci_save_initial_config(struct device *dev,
 | |
|  	hpriv->cap = cap;
 | |
|  	hpriv->cap2 = cap2;
 | |
|  	hpriv->port_map = port_map;
 | |
| +
 | |
| +	if (!hpriv->start_engine)
 | |
| +		hpriv->start_engine = ahci_start_engine;
 | |
|  }
 | |
|  EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 | |
|  
 | |
| @@ -766,7 +772,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) {
 | |
| @@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
 | |
|  
 | |
|  	/* restart engine */
 | |
|   out_restart:
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  	return rc;
 | |
|  }
 | |
|  EXPORT_SYMBOL_GPL(ahci_kick_engine);
 | |
| @@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 | |
|  	struct ata_port *ap = link->ap;
 | |
|  	struct ahci_port_priv *pp = ap->private_data;
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 | |
|  	struct ata_taskfile tf;
 | |
|  	bool online;
 | |
| @@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  	rc = sata_link_hardreset(link, timing, deadline, &online,
 | |
|  				 ahci_check_ready);
 | |
|  
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  
 | |
|  	if (online)
 | |
|  		*class = ahci_dev_classify(ap);
 | |
| @@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
 | |
|  
 | |
|  void ahci_error_handler(struct ata_port *ap)
 | |
|  {
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
| +
 | |
|  	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
 | |
|  		/* restart engine */
 | |
|  		ahci_stop_engine(ap);
 | |
| -		ahci_start_engine(ap);
 | |
| +		hpriv->start_engine(ap);
 | |
|  	}
 | |
|  
 | |
|  	sata_pmp_error_handler(ap);
 | |
| @@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 | |
|  
 | |
|  static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 | |
|  {
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	void __iomem *port_mmio = ahci_port_base(ap);
 | |
|  	struct ata_device *dev = ap->link.device;
 | |
|  	u32 devslp, dm, dito, mdat, deto;
 | |
| @@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 | |
|  		   PORT_DEVSLP_ADSE);
 | |
|  	writel(devslp, port_mmio + PORT_DEVSLP);
 | |
|  
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  
 | |
|  	/* enable device sleep feature for the drive */
 | |
|  	err_mask = ata_dev_set_feature(dev,
 | |
| @@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 | |
|  
 | |
|  static void ahci_enable_fbs(struct ata_port *ap)
 | |
|  {
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	struct ahci_port_priv *pp = ap->private_data;
 | |
|  	void __iomem *port_mmio = ahci_port_base(ap);
 | |
|  	u32 fbs;
 | |
| @@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
 | |
|  	} else
 | |
|  		dev_err(ap->host->dev, "Failed to enable FBS\n");
 | |
|  
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  }
 | |
|  
 | |
|  static void ahci_disable_fbs(struct ata_port *ap)
 | |
|  {
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	struct ahci_port_priv *pp = ap->private_data;
 | |
|  	void __iomem *port_mmio = ahci_port_base(ap);
 | |
|  	u32 fbs;
 | |
| @@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
 | |
|  		pp->fbs_enabled = false;
 | |
|  	}
 | |
|  
 | |
| -	ahci_start_engine(ap);
 | |
| +	hpriv->start_engine(ap);
 | |
|  }
 | |
|  
 | |
|  static void ahci_pmp_attach(struct ata_port *ap)
 | |
| diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
 | |
| index 870b11e..b3b18d1 100644
 | |
| --- a/drivers/ata/sata_highbank.c
 | |
| +++ b/drivers/ata/sata_highbank.c
 | |
| @@ -403,6 +403,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
 | |
|  	static const unsigned long timing[] = { 5, 100, 500};
 | |
|  	struct ata_port *ap = link->ap;
 | |
|  	struct ahci_port_priv *pp = ap->private_data;
 | |
| +	struct ahci_host_priv *hpriv = ap->host->private_data;
 | |
|  	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 | |
|  	struct ata_taskfile tf;
 | |
|  	bool online;
 | |
| @@ -431,7 +432,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);
 | |
| -- 
 | |
| 1.8.5.5
 | |
| 
 |