diff options
Diffstat (limited to 'drivers/ata/pata_bf54x.c')
| -rw-r--r-- | drivers/ata/pata_bf54x.c | 215 | 
1 files changed, 102 insertions, 113 deletions
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 7aed5c79259..03f2f2bc83b 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -251,6 +251,8 @@ static const u32 udma_tenvmin = 20;  static const u32 udma_tackmin = 20;  static const u32 udma_tssmin = 50; +#define BFIN_MAX_SG_SEGMENTS 4 +  /**   *   *	Function:       num_clocks_min @@ -418,14 +420,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)  					(tcyc_tdvs<<8 | tdvs));  				ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));  				ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah)); - -				/* Enable host ATAPI Untra DMA interrupts */ -				ATAPI_SET_INT_MASK(base, -					ATAPI_GET_INT_MASK(base) -					| UDMAIN_DONE_MASK -					| UDMAOUT_DONE_MASK -					| UDMAIN_TERM_MASK -					| UDMAOUT_TERM_MASK);  			}  		}  	} @@ -470,10 +464,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)  			ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));  			ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));  			ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th)); - -			/* Enable host ATAPI Multi DMA interrupts */ -			ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) -				| MULTI_DONE_MASK | MULTI_TERM_MASK);  			SSYNC();  		}  	} @@ -841,79 +831,61 @@ static void bfin_set_devctl(struct ata_port *ap, u8 ctl)  static void bfin_bmdma_setup(struct ata_queued_cmd *qc)  { -	unsigned short config = WDSIZE_16; +	struct ata_port *ap = qc->ap; +	struct dma_desc_array *dma_desc_cpu = (struct dma_desc_array *)ap->bmdma_prd; +	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; +	unsigned short config = DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_16 | DMAEN;  	struct scatterlist *sg;  	unsigned int si; +	unsigned int channel; +	unsigned int dir; +	unsigned int size = 0;  	dev_dbg(qc->ap->dev, "in atapi dma setup\n");  	/* Program the ATA_CTRL register with dir */  	if (qc->tf.flags & ATA_TFLAG_WRITE) { -		/* fill the ATAPI DMA controller */ -		set_dma_config(CH_ATAPI_TX, config); -		set_dma_x_modify(CH_ATAPI_TX, 2); -		for_each_sg(qc->sg, sg, qc->n_elem, si) { -			set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); -			set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); -		} +		channel = CH_ATAPI_TX; +		dir = DMA_TO_DEVICE;  	} else { +		channel = CH_ATAPI_RX; +		dir = DMA_FROM_DEVICE;  		config |= WNR; -		/* fill the ATAPI DMA controller */ -		set_dma_config(CH_ATAPI_RX, config); -		set_dma_x_modify(CH_ATAPI_RX, 2); -		for_each_sg(qc->sg, sg, qc->n_elem, si) { -			set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); -			set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); -		}  	} -} -/** - *	bfin_bmdma_start - Start an IDE DMA transaction - *	@qc: Info associated with this ATA transaction. - * - *	Note: Original code is ata_bmdma_start(). - */ +	dma_map_sg(ap->dev, qc->sg, qc->n_elem, dir); -static void bfin_bmdma_start(struct ata_queued_cmd *qc) -{ -	struct ata_port *ap = qc->ap; -	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; -	struct scatterlist *sg; -	unsigned int si; +	/* fill the ATAPI DMA controller */ +	for_each_sg(qc->sg, sg, qc->n_elem, si) { +		dma_desc_cpu[si].start_addr = sg_dma_address(sg); +		dma_desc_cpu[si].cfg = config; +		dma_desc_cpu[si].x_count = sg_dma_len(sg) >> 1; +		dma_desc_cpu[si].x_modify = 2; +		size += sg_dma_len(sg); +	} -	dev_dbg(qc->ap->dev, "in atapi dma start\n"); -	if (!(ap->udma_mask || ap->mwdma_mask)) -		return; +	/* Set the last descriptor to stop mode */ +	dma_desc_cpu[qc->n_elem - 1].cfg &= ~(DMAFLOW | NDSIZE); -	/* start ATAPI DMA controller*/ -	if (qc->tf.flags & ATA_TFLAG_WRITE) { -		/* -		 * On blackfin arch, uncacheable memory is not -		 * allocated with flag GFP_DMA. DMA buffer from -		 * common kenel code should be flushed if WB -		 * data cache is enabled. Otherwise, this loop -		 * is an empty loop and optimized out. -		 */ -		for_each_sg(qc->sg, sg, qc->n_elem, si) { -			flush_dcache_range(sg_dma_address(sg), -				sg_dma_address(sg) + sg_dma_len(sg)); -		} -		enable_dma(CH_ATAPI_TX); -		dev_dbg(qc->ap->dev, "enable udma write\n"); +	flush_dcache_range((unsigned int)dma_desc_cpu, +		(unsigned int)dma_desc_cpu + +			qc->n_elem * sizeof(struct dma_desc_array)); + +	/* Enable ATA DMA operation*/ +	set_dma_curr_desc_addr(channel, (unsigned long *)ap->bmdma_prd_dma); +	set_dma_x_count(channel, 0); +	set_dma_x_modify(channel, 0); +	set_dma_config(channel, config); + +	SSYNC(); -		/* Send ATA DMA write command */ -		bfin_exec_command(ap, &qc->tf); +	/* Send ATA DMA command */ +	bfin_exec_command(ap, &qc->tf); +	if (qc->tf.flags & ATA_TFLAG_WRITE) {  		/* set ATA DMA write direction */  		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)  			| XFER_DIR));  	} else { -		enable_dma(CH_ATAPI_RX); -		dev_dbg(qc->ap->dev, "enable udma read\n"); - -		/* Send ATA DMA read command */ -		bfin_exec_command(ap, &qc->tf); -  		/* set ATA DMA read direction */  		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)  			& ~XFER_DIR)); @@ -925,12 +897,28 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)  	/* Set ATAPI state machine contorl in terminate sequence */  	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM); -	/* Set transfer length to buffer len */ -	for_each_sg(qc->sg, sg, qc->n_elem, si) { -		ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); -	} +	/* Set transfer length to the total size of sg buffers */ +	ATAPI_SET_XFER_LEN(base, size >> 1); +} -	/* Enable ATA DMA operation*/ +/** + *	bfin_bmdma_start - Start an IDE DMA transaction + *	@qc: Info associated with this ATA transaction. + * + *	Note: Original code is ata_bmdma_start(). + */ + +static void bfin_bmdma_start(struct ata_queued_cmd *qc) +{ +	struct ata_port *ap = qc->ap; +	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + +	dev_dbg(qc->ap->dev, "in atapi dma start\n"); + +	if (!(ap->udma_mask || ap->mwdma_mask)) +		return; + +	/* start ATAPI transfer*/  	if (ap->udma_mask)  		ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)  			| ULTRA_START); @@ -947,34 +935,23 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)  static void bfin_bmdma_stop(struct ata_queued_cmd *qc)  {  	struct ata_port *ap = qc->ap; -	struct scatterlist *sg; -	unsigned int si; +	unsigned int dir;  	dev_dbg(qc->ap->dev, "in atapi dma stop\n"); +  	if (!(ap->udma_mask || ap->mwdma_mask))  		return;  	/* stop ATAPI DMA controller*/ -	if (qc->tf.flags & ATA_TFLAG_WRITE) +	if (qc->tf.flags & ATA_TFLAG_WRITE) { +		dir = DMA_TO_DEVICE;  		disable_dma(CH_ATAPI_TX); -	else { +	} else { +		dir = DMA_FROM_DEVICE;  		disable_dma(CH_ATAPI_RX); -		if (ap->hsm_task_state & HSM_ST_LAST) { -			/* -			 * On blackfin arch, uncacheable memory is not -			 * allocated with flag GFP_DMA. DMA buffer from -			 * common kenel code should be invalidated if -			 * data cache is enabled. Otherwise, this loop -			 * is an empty loop and optimized out. -			 */ -			for_each_sg(qc->sg, sg, qc->n_elem, si) { -				invalidate_dcache_range( -					sg_dma_address(sg), -					sg_dma_address(sg) -					+ sg_dma_len(sg)); -			} -		}  	} + +	dma_unmap_sg(ap->dev, qc->sg, qc->n_elem, dir);  }  /** @@ -1129,7 +1106,7 @@ static int bfin_softreset(struct ata_link *link, unsigned int *classes,  	/* issue bus reset */  	err_mask = bfin_bus_softreset(ap, devmask);  	if (err_mask) { -		ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", +		ata_port_err(ap, "SRST failed (err_mask=0x%x)\n",  				err_mask);  		return -EIO;  	} @@ -1153,15 +1130,11 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)  {  	unsigned char host_stat = 0;  	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; -	unsigned short int_status = ATAPI_GET_INT_STATUS(base); -	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) +	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON | ULTRA_XFER_ON))  		host_stat |= ATA_DMA_ACTIVE; -	if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT| -		ATAPI_DEV_INT)) +	if (ATAPI_GET_INT_STATUS(base) & ATAPI_DEV_INT)  		host_stat |= ATA_DMA_INTR; -	if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) -		host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;  	dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat); @@ -1276,6 +1249,11 @@ static void bfin_port_stop(struct ata_port *ap)  {  	dev_dbg(ap->dev, "in atapi port stop\n");  	if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { +		dma_free_coherent(ap->dev, +			BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), +			ap->bmdma_prd, +			ap->bmdma_prd_dma); +  		free_dma(CH_ATAPI_RX);  		free_dma(CH_ATAPI_TX);  	} @@ -1287,14 +1265,29 @@ static int bfin_port_start(struct ata_port *ap)  	if (!(ap->udma_mask || ap->mwdma_mask))  		return 0; +	ap->bmdma_prd = dma_alloc_coherent(ap->dev, +				BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), +				&ap->bmdma_prd_dma, +				GFP_KERNEL); + +	if (ap->bmdma_prd == NULL) { +		dev_info(ap->dev, "Unable to allocate DMA descriptor array.\n"); +		goto out; +	} +  	if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {  		if (request_dma(CH_ATAPI_TX,  			"BFIN ATAPI TX DMA") >= 0)  			return 0;  		free_dma(CH_ATAPI_RX); +		dma_free_coherent(ap->dev, +			BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), +			ap->bmdma_prd, +			ap->bmdma_prd_dma);  	} +out:  	ap->udma_mask = 0;  	ap->mwdma_mask = 0;  	dev_err(ap->dev, "Unable to request ATAPI DMA!" @@ -1342,7 +1335,7 @@ static unsigned int bfin_ata_host_intr(struct ata_port *ap,  			ap->ops->bmdma_stop(qc);  			if (unlikely(host_stat & ATA_DMA_ERR)) { -				/* error when transfering data to/from memory */ +				/* error when transferring data to/from memory */  				qc->err_mask |= AC_ERR_HOST_BUS;  				ap->hsm_task_state = HSM_ST_ERR;  			} @@ -1382,7 +1375,7 @@ idle_irq:  #ifdef ATA_IRQ_TRAP  	if ((ap->stats.idle_irq % 1000) == 0) {  		ap->ops->irq_ack(ap, 0); /* debug trap */ -		ata_port_printk(ap, KERN_WARNING, "irq trap\n"); +		ata_port_warn(ap, "irq trap\n");  		return 1;  	}  #endif @@ -1416,7 +1409,7 @@ static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)  static struct scsi_host_template bfin_sht = {  	ATA_BASE_SHT(DRV_NAME), -	.sg_tablesize		= SG_NONE, +	.sg_tablesize		= BFIN_MAX_SG_SEGMENTS,  	.dma_boundary		= ATA_DMA_BOUNDARY,  }; @@ -1454,9 +1447,7 @@ static struct ata_port_operations bfin_pata_ops = {  static struct ata_port_info bfin_port_info[] = {  	{ -		.flags		= ATA_FLAG_SLAVE_POSS -				| ATA_FLAG_MMIO -				| ATA_FLAG_NO_LEGACY, +		.flags		= ATA_FLAG_SLAVE_POSS,  		.pio_mask	= ATA_PIO4,  		.mwdma_mask	= 0,  		.udma_mask	= 0, @@ -1547,7 +1538,7 @@ static unsigned short atapi_io_port[] = {   *		- IRQ	   (IORESOURCE_IRQ)   *   */ -static int __devinit bfin_atapi_probe(struct platform_device *pdev) +static int bfin_atapi_probe(struct platform_device *pdev)  {  	int board_idx = 0;  	struct resource *res; @@ -1605,7 +1596,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	dev_set_drvdata(&pdev->dev, host); +	platform_set_drvdata(pdev, host);  	return 0;  } @@ -1617,23 +1608,21 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)   *	A bfin atapi device has been unplugged. Perform the needed   *	cleanup. Also called on module unload for any active devices.   */ -static int __devexit bfin_atapi_remove(struct platform_device *pdev) +static int bfin_atapi_remove(struct platform_device *pdev)  { -	struct device *dev = &pdev->dev; -	struct ata_host *host = dev_get_drvdata(dev); +	struct ata_host *host = platform_get_drvdata(pdev);  	ata_host_detach(host); -	dev_set_drvdata(&pdev->dev, NULL);  	peripheral_free_list(atapi_io_port);  	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 = dev_get_drvdata(&pdev->dev); +	struct ata_host *host = platform_get_drvdata(pdev);  	if (host)  		return ata_host_suspend(host, state);  	else @@ -1642,7 +1631,7 @@ static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)  static int bfin_atapi_resume(struct platform_device *pdev)  { -	struct ata_host *host = dev_get_drvdata(&pdev->dev); +	struct ata_host *host = platform_get_drvdata(pdev);  	int ret;  	if (host) { @@ -1663,7 +1652,7 @@ static int bfin_atapi_resume(struct platform_device *pdev)  static struct platform_driver bfin_atapi_driver = {  	.probe			= bfin_atapi_probe, -	.remove			= __devexit_p(bfin_atapi_remove), +	.remove			= bfin_atapi_remove,  	.suspend		= bfin_atapi_suspend,  	.resume			= bfin_atapi_resume,  	.driver = {  | 
