| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  *  pdc_adma.c - Pacific Digital Corporation ADMA | 
 | 3 |  * | 
 | 4 |  *  Maintained by:  Mark Lord <mlord@pobox.com> | 
 | 5 |  * | 
 | 6 |  *  Copyright 2005 Mark Lord | 
 | 7 |  * | 
| Jeff Garzik | 68399bb | 2005-10-11 01:44:14 -0400 | [diff] [blame] | 8 |  *  This program is free software; you can redistribute it and/or modify | 
 | 9 |  *  it under the terms of the GNU General Public License as published by | 
 | 10 |  *  the Free Software Foundation; either version 2, or (at your option) | 
 | 11 |  *  any later version. | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 12 |  * | 
| Jeff Garzik | 68399bb | 2005-10-11 01:44:14 -0400 | [diff] [blame] | 13 |  *  This program is distributed in the hope that it will be useful, | 
 | 14 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 15 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 16 |  *  GNU General Public License for more details. | 
 | 17 |  * | 
 | 18 |  *  You should have received a copy of the GNU General Public License | 
 | 19 |  *  along with this program; see the file COPYING.  If not, write to | 
 | 20 |  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 21 |  * | 
 | 22 |  * | 
 | 23 |  *  libata documentation is available via 'make {ps|pdf}docs', | 
 | 24 |  *  as Documentation/DocBook/libata.* | 
 | 25 |  * | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 26 |  * | 
 | 27 |  *  Supports ATA disks in single-packet ADMA mode. | 
 | 28 |  *  Uses PIO for everything else. | 
 | 29 |  * | 
 | 30 |  *  TODO:  Use ADMA transfers for ATAPI devices, when possible. | 
 | 31 |  *  This requires careful attention to a number of quirks of the chip. | 
 | 32 |  * | 
 | 33 |  */ | 
 | 34 |  | 
 | 35 | #include <linux/kernel.h> | 
 | 36 | #include <linux/module.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 37 | #include <linux/gfp.h> | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 38 | #include <linux/pci.h> | 
 | 39 | #include <linux/init.h> | 
 | 40 | #include <linux/blkdev.h> | 
 | 41 | #include <linux/delay.h> | 
 | 42 | #include <linux/interrupt.h> | 
| Jeff Garzik | a9524a7 | 2005-10-30 14:39:11 -0500 | [diff] [blame] | 43 | #include <linux/device.h> | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 44 | #include <scsi/scsi_host.h> | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 45 | #include <linux/libata.h> | 
 | 46 |  | 
 | 47 | #define DRV_NAME	"pdc_adma" | 
| Jeff Garzik | 2a3103c | 2007-08-31 04:54:06 -0400 | [diff] [blame] | 48 | #define DRV_VERSION	"1.0" | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 49 |  | 
 | 50 | /* macro to calculate base address for ATA regs */ | 
| Jeff Garzik | 5796d1c | 2007-10-26 00:03:37 -0400 | [diff] [blame] | 51 | #define ADMA_ATA_REGS(base, port_no)	((base) + ((port_no) * 0x40)) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 52 |  | 
 | 53 | /* macro to calculate base address for ADMA regs */ | 
| Jeff Garzik | 5796d1c | 2007-10-26 00:03:37 -0400 | [diff] [blame] | 54 | #define ADMA_REGS(base, port_no)	((base) + 0x80 + ((port_no) * 0x20)) | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 55 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 56 | /* macro to obtain addresses from ata_port */ | 
 | 57 | #define ADMA_PORT_REGS(ap) \ | 
 | 58 | 	ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 59 |  | 
 | 60 | enum { | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 61 | 	ADMA_MMIO_BAR		= 4, | 
 | 62 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 63 | 	ADMA_PORTS		= 2, | 
 | 64 | 	ADMA_CPB_BYTES		= 40, | 
 | 65 | 	ADMA_PRD_BYTES		= LIBATA_MAX_PRD * 16, | 
 | 66 | 	ADMA_PKT_BYTES		= ADMA_CPB_BYTES + ADMA_PRD_BYTES, | 
 | 67 |  | 
 | 68 | 	ADMA_DMA_BOUNDARY	= 0xffffffff, | 
 | 69 |  | 
 | 70 | 	/* global register offsets */ | 
 | 71 | 	ADMA_MODE_LOCK		= 0x00c7, | 
 | 72 |  | 
 | 73 | 	/* per-channel register offsets */ | 
 | 74 | 	ADMA_CONTROL		= 0x0000, /* ADMA control */ | 
 | 75 | 	ADMA_STATUS		= 0x0002, /* ADMA status */ | 
 | 76 | 	ADMA_CPB_COUNT		= 0x0004, /* CPB count */ | 
 | 77 | 	ADMA_CPB_CURRENT	= 0x000c, /* current CPB address */ | 
 | 78 | 	ADMA_CPB_NEXT		= 0x000c, /* next CPB address */ | 
 | 79 | 	ADMA_CPB_LOOKUP		= 0x0010, /* CPB lookup table */ | 
 | 80 | 	ADMA_FIFO_IN		= 0x0014, /* input FIFO threshold */ | 
 | 81 | 	ADMA_FIFO_OUT		= 0x0016, /* output FIFO threshold */ | 
 | 82 |  | 
 | 83 | 	/* ADMA_CONTROL register bits */ | 
 | 84 | 	aNIEN			= (1 << 8), /* irq mask: 1==masked */ | 
 | 85 | 	aGO			= (1 << 7), /* packet trigger ("Go!") */ | 
 | 86 | 	aRSTADM			= (1 << 5), /* ADMA logic reset */ | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 87 | 	aPIOMD4			= 0x0003,   /* PIO mode 4 */ | 
 | 88 |  | 
 | 89 | 	/* ADMA_STATUS register bits */ | 
 | 90 | 	aPSD			= (1 << 6), | 
 | 91 | 	aUIRQ			= (1 << 4), | 
 | 92 | 	aPERR			= (1 << 0), | 
 | 93 |  | 
 | 94 | 	/* CPB bits */ | 
 | 95 | 	cDONE			= (1 << 0), | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 96 | 	cATERR			= (1 << 3), | 
 | 97 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 98 | 	cVLD			= (1 << 0), | 
 | 99 | 	cDAT			= (1 << 2), | 
 | 100 | 	cIEN			= (1 << 3), | 
 | 101 |  | 
 | 102 | 	/* PRD bits */ | 
 | 103 | 	pORD			= (1 << 4), | 
 | 104 | 	pDIRO			= (1 << 5), | 
 | 105 | 	pEND			= (1 << 7), | 
 | 106 |  | 
 | 107 | 	/* ATA register flags */ | 
 | 108 | 	rIGN			= (1 << 5), | 
 | 109 | 	rEND			= (1 << 7), | 
 | 110 |  | 
 | 111 | 	/* ATA register addresses */ | 
 | 112 | 	ADMA_REGS_CONTROL	= 0x0e, | 
 | 113 | 	ADMA_REGS_SECTOR_COUNT	= 0x12, | 
 | 114 | 	ADMA_REGS_LBA_LOW	= 0x13, | 
 | 115 | 	ADMA_REGS_LBA_MID	= 0x14, | 
 | 116 | 	ADMA_REGS_LBA_HIGH	= 0x15, | 
 | 117 | 	ADMA_REGS_DEVICE	= 0x16, | 
 | 118 | 	ADMA_REGS_COMMAND	= 0x17, | 
 | 119 |  | 
 | 120 | 	/* PCI device IDs */ | 
 | 121 | 	board_1841_idx		= 0,	/* ADMA 2-port controller */ | 
 | 122 | }; | 
 | 123 |  | 
 | 124 | typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t; | 
 | 125 |  | 
 | 126 | struct adma_port_priv { | 
 | 127 | 	u8			*pkt; | 
 | 128 | 	dma_addr_t		pkt_dma; | 
 | 129 | 	adma_state_t		state; | 
 | 130 | }; | 
 | 131 |  | 
| Jeff Garzik | 5796d1c | 2007-10-26 00:03:37 -0400 | [diff] [blame] | 132 | static int adma_ata_init_one(struct pci_dev *pdev, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 133 | 				const struct pci_device_id *ent); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 134 | static int adma_port_start(struct ata_port *ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 135 | static void adma_port_stop(struct ata_port *ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 136 | static void adma_qc_prep(struct ata_queued_cmd *qc); | 
| Tejun Heo | 9a3d9eb | 2006-01-23 13:09:36 +0900 | [diff] [blame] | 137 | static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 138 | static int adma_check_atapi_dma(struct ata_queued_cmd *qc); | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 139 | static void adma_freeze(struct ata_port *ap); | 
 | 140 | static void adma_thaw(struct ata_port *ap); | 
| Tejun Heo | a1efdab | 2008-03-25 12:22:50 +0900 | [diff] [blame] | 141 | static int adma_prereset(struct ata_link *link, unsigned long deadline); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 142 |  | 
| Jeff Garzik | 193515d | 2005-11-07 00:59:37 -0500 | [diff] [blame] | 143 | static struct scsi_host_template adma_ata_sht = { | 
| Tejun Heo | 68d1d07 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 144 | 	ATA_BASE_SHT(DRV_NAME), | 
| Jeff Garzik | 49de0ac | 2007-05-26 18:20:51 -0400 | [diff] [blame] | 145 | 	.sg_tablesize		= LIBATA_MAX_PRD, | 
 | 146 | 	.dma_boundary		= ADMA_DMA_BOUNDARY, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 147 | }; | 
 | 148 |  | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 149 | static struct ata_port_operations adma_ata_ops = { | 
| Tejun Heo | b0316b1 | 2008-03-25 21:35:30 +0900 | [diff] [blame] | 150 | 	.inherits		= &ata_sff_port_ops, | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 151 |  | 
| Alan Cox | c96f173 | 2009-03-24 10:23:46 +0000 | [diff] [blame] | 152 | 	.lost_interrupt		= ATA_OP_NULL, | 
 | 153 |  | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 154 | 	.check_atapi_dma	= adma_check_atapi_dma, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 155 | 	.qc_prep		= adma_qc_prep, | 
 | 156 | 	.qc_issue		= adma_qc_issue, | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 157 |  | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 158 | 	.freeze			= adma_freeze, | 
 | 159 | 	.thaw			= adma_thaw, | 
| Tejun Heo | a1efdab | 2008-03-25 12:22:50 +0900 | [diff] [blame] | 160 | 	.prereset		= adma_prereset, | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 161 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 162 | 	.port_start		= adma_port_start, | 
 | 163 | 	.port_stop		= adma_port_stop, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 164 | }; | 
 | 165 |  | 
 | 166 | static struct ata_port_info adma_port_info[] = { | 
 | 167 | 	/* board_1841_idx */ | 
 | 168 | 	{ | 
| Sergei Shtylyov | 9cbe056 | 2011-02-04 22:05:48 +0300 | [diff] [blame] | 169 | 		.flags		= ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING, | 
| Erik Inge Bolsø | 14bdef9 | 2009-03-14 21:38:24 +0100 | [diff] [blame] | 170 | 		.pio_mask	= ATA_PIO4_ONLY, | 
| Jeff Garzik | bf6263a | 2007-07-09 12:16:50 -0400 | [diff] [blame] | 171 | 		.udma_mask	= ATA_UDMA4, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 172 | 		.port_ops	= &adma_ata_ops, | 
 | 173 | 	}, | 
 | 174 | }; | 
 | 175 |  | 
| Jeff Garzik | 3b7d697 | 2005-11-10 11:04:11 -0500 | [diff] [blame] | 176 | static const struct pci_device_id adma_ata_pci_tbl[] = { | 
| Jeff Garzik | 54bb3a9 | 2006-09-27 22:20:11 -0400 | [diff] [blame] | 177 | 	{ PCI_VDEVICE(PDC, 0x1841), board_1841_idx }, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 178 |  | 
 | 179 | 	{ }	/* terminate list */ | 
 | 180 | }; | 
 | 181 |  | 
 | 182 | static struct pci_driver adma_ata_pci_driver = { | 
 | 183 | 	.name			= DRV_NAME, | 
 | 184 | 	.id_table		= adma_ata_pci_tbl, | 
 | 185 | 	.probe			= adma_ata_init_one, | 
 | 186 | 	.remove			= ata_pci_remove_one, | 
 | 187 | }; | 
 | 188 |  | 
 | 189 | static int adma_check_atapi_dma(struct ata_queued_cmd *qc) | 
 | 190 | { | 
 | 191 | 	return 1;	/* ATAPI DMA not yet supported */ | 
 | 192 | } | 
 | 193 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 194 | static void adma_reset_engine(struct ata_port *ap) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 195 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 196 | 	void __iomem *chan = ADMA_PORT_REGS(ap); | 
 | 197 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 198 | 	/* reset ADMA to idle state */ | 
 | 199 | 	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); | 
 | 200 | 	udelay(2); | 
 | 201 | 	writew(aPIOMD4, chan + ADMA_CONTROL); | 
 | 202 | 	udelay(2); | 
 | 203 | } | 
 | 204 |  | 
 | 205 | static void adma_reinit_engine(struct ata_port *ap) | 
 | 206 | { | 
 | 207 | 	struct adma_port_priv *pp = ap->private_data; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 208 | 	void __iomem *chan = ADMA_PORT_REGS(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 209 |  | 
 | 210 | 	/* mask/clear ATA interrupts */ | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 211 | 	writeb(ATA_NIEN, ap->ioaddr.ctl_addr); | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 212 | 	ata_sff_check_status(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 213 |  | 
 | 214 | 	/* reset the ADMA engine */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 215 | 	adma_reset_engine(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 216 |  | 
 | 217 | 	/* set in-FIFO threshold to 0x100 */ | 
 | 218 | 	writew(0x100, chan + ADMA_FIFO_IN); | 
 | 219 |  | 
 | 220 | 	/* set CPB pointer */ | 
 | 221 | 	writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT); | 
 | 222 |  | 
 | 223 | 	/* set out-FIFO threshold to 0x100 */ | 
 | 224 | 	writew(0x100, chan + ADMA_FIFO_OUT); | 
 | 225 |  | 
 | 226 | 	/* set CPB count */ | 
 | 227 | 	writew(1, chan + ADMA_CPB_COUNT); | 
 | 228 |  | 
 | 229 | 	/* read/discard ADMA status */ | 
 | 230 | 	readb(chan + ADMA_STATUS); | 
 | 231 | } | 
 | 232 |  | 
 | 233 | static inline void adma_enter_reg_mode(struct ata_port *ap) | 
 | 234 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 235 | 	void __iomem *chan = ADMA_PORT_REGS(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 236 |  | 
 | 237 | 	writew(aPIOMD4, chan + ADMA_CONTROL); | 
 | 238 | 	readb(chan + ADMA_STATUS);	/* flush */ | 
 | 239 | } | 
 | 240 |  | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 241 | static void adma_freeze(struct ata_port *ap) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 242 | { | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 243 | 	void __iomem *chan = ADMA_PORT_REGS(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 244 |  | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 245 | 	/* mask/clear ATA interrupts */ | 
 | 246 | 	writeb(ATA_NIEN, ap->ioaddr.ctl_addr); | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 247 | 	ata_sff_check_status(ap); | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 248 |  | 
 | 249 | 	/* reset ADMA to idle state */ | 
 | 250 | 	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); | 
 | 251 | 	udelay(2); | 
 | 252 | 	writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); | 
 | 253 | 	udelay(2); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 254 | } | 
 | 255 |  | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 256 | static void adma_thaw(struct ata_port *ap) | 
 | 257 | { | 
 | 258 | 	adma_reinit_engine(ap); | 
 | 259 | } | 
 | 260 |  | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 261 | static int adma_prereset(struct ata_link *link, unsigned long deadline) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 262 | { | 
| Tejun Heo | 0260731 | 2007-08-06 18:36:23 +0900 | [diff] [blame] | 263 | 	struct ata_port *ap = link->ap; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 264 | 	struct adma_port_priv *pp = ap->private_data; | 
 | 265 |  | 
 | 266 | 	if (pp->state != adma_state_idle) /* healthy paranoia */ | 
 | 267 | 		pp->state = adma_state_mmio; | 
 | 268 | 	adma_reinit_engine(ap); | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 269 |  | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 270 | 	return ata_sff_prereset(link, deadline); | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 271 | } | 
 | 272 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 273 | static int adma_fill_sg(struct ata_queued_cmd *qc) | 
 | 274 | { | 
| Jeff Garzik | 972c26b | 2005-10-18 22:14:54 -0400 | [diff] [blame] | 275 | 	struct scatterlist *sg; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 276 | 	struct ata_port *ap = qc->ap; | 
 | 277 | 	struct adma_port_priv *pp = ap->private_data; | 
| Jeff Garzik | 3be6cbd | 2007-10-18 16:21:18 -0400 | [diff] [blame] | 278 | 	u8  *buf = pp->pkt, *last_buf = NULL; | 
| Jeff Garzik | 972c26b | 2005-10-18 22:14:54 -0400 | [diff] [blame] | 279 | 	int i = (2 + buf[3]) * 8; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 280 | 	u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); | 
| Tejun Heo | ff2aeb1 | 2007-12-05 16:43:11 +0900 | [diff] [blame] | 281 | 	unsigned int si; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 282 |  | 
| Tejun Heo | ff2aeb1 | 2007-12-05 16:43:11 +0900 | [diff] [blame] | 283 | 	for_each_sg(qc->sg, sg, qc->n_elem, si) { | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 284 | 		u32 addr; | 
 | 285 | 		u32 len; | 
 | 286 |  | 
 | 287 | 		addr = (u32)sg_dma_address(sg); | 
 | 288 | 		*(__le32 *)(buf + i) = cpu_to_le32(addr); | 
 | 289 | 		i += 4; | 
 | 290 |  | 
 | 291 | 		len = sg_dma_len(sg) >> 3; | 
 | 292 | 		*(__le32 *)(buf + i) = cpu_to_le32(len); | 
 | 293 | 		i += 4; | 
 | 294 |  | 
| Jeff Garzik | 3be6cbd | 2007-10-18 16:21:18 -0400 | [diff] [blame] | 295 | 		last_buf = &buf[i]; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 296 | 		buf[i++] = pFLAGS; | 
 | 297 | 		buf[i++] = qc->dev->dma_mode & 0xf; | 
 | 298 | 		buf[i++] = 0;	/* pPKLW */ | 
 | 299 | 		buf[i++] = 0;	/* reserved */ | 
 | 300 |  | 
| Jeff Garzik | 5796d1c | 2007-10-26 00:03:37 -0400 | [diff] [blame] | 301 | 		*(__le32 *)(buf + i) = | 
 | 302 | 			(pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 303 | 		i += 4; | 
 | 304 |  | 
| Alan Cox | db7f44d | 2006-03-21 15:54:24 +0000 | [diff] [blame] | 305 | 		VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4, | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 306 | 					(unsigned long)addr, len); | 
 | 307 | 	} | 
| Jeff Garzik | 3be6cbd | 2007-10-18 16:21:18 -0400 | [diff] [blame] | 308 |  | 
 | 309 | 	if (likely(last_buf)) | 
 | 310 | 		*last_buf |= pEND; | 
 | 311 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 312 | 	return i; | 
 | 313 | } | 
 | 314 |  | 
 | 315 | static void adma_qc_prep(struct ata_queued_cmd *qc) | 
 | 316 | { | 
 | 317 | 	struct adma_port_priv *pp = qc->ap->private_data; | 
 | 318 | 	u8  *buf = pp->pkt; | 
 | 319 | 	u32 pkt_dma = (u32)pp->pkt_dma; | 
 | 320 | 	int i = 0; | 
 | 321 |  | 
 | 322 | 	VPRINTK("ENTER\n"); | 
 | 323 |  | 
 | 324 | 	adma_enter_reg_mode(qc->ap); | 
| Tejun Heo | f47451c | 2010-05-10 21:41:40 +0200 | [diff] [blame] | 325 | 	if (qc->tf.protocol != ATA_PROT_DMA) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 326 | 		return; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 327 |  | 
 | 328 | 	buf[i++] = 0;	/* Response flags */ | 
 | 329 | 	buf[i++] = 0;	/* reserved */ | 
 | 330 | 	buf[i++] = cVLD | cDAT | cIEN; | 
 | 331 | 	i++;		/* cLEN, gets filled in below */ | 
 | 332 |  | 
 | 333 | 	*(__le32 *)(buf+i) = cpu_to_le32(pkt_dma);	/* cNCPB */ | 
 | 334 | 	i += 4;		/* cNCPB */ | 
 | 335 | 	i += 4;		/* cPRD, gets filled in below */ | 
 | 336 |  | 
 | 337 | 	buf[i++] = 0;	/* reserved */ | 
 | 338 | 	buf[i++] = 0;	/* reserved */ | 
 | 339 | 	buf[i++] = 0;	/* reserved */ | 
 | 340 | 	buf[i++] = 0;	/* reserved */ | 
 | 341 |  | 
 | 342 | 	/* ATA registers; must be a multiple of 4 */ | 
 | 343 | 	buf[i++] = qc->tf.device; | 
 | 344 | 	buf[i++] = ADMA_REGS_DEVICE; | 
 | 345 | 	if ((qc->tf.flags & ATA_TFLAG_LBA48)) { | 
 | 346 | 		buf[i++] = qc->tf.hob_nsect; | 
 | 347 | 		buf[i++] = ADMA_REGS_SECTOR_COUNT; | 
 | 348 | 		buf[i++] = qc->tf.hob_lbal; | 
 | 349 | 		buf[i++] = ADMA_REGS_LBA_LOW; | 
 | 350 | 		buf[i++] = qc->tf.hob_lbam; | 
 | 351 | 		buf[i++] = ADMA_REGS_LBA_MID; | 
 | 352 | 		buf[i++] = qc->tf.hob_lbah; | 
 | 353 | 		buf[i++] = ADMA_REGS_LBA_HIGH; | 
 | 354 | 	} | 
 | 355 | 	buf[i++] = qc->tf.nsect; | 
 | 356 | 	buf[i++] = ADMA_REGS_SECTOR_COUNT; | 
 | 357 | 	buf[i++] = qc->tf.lbal; | 
 | 358 | 	buf[i++] = ADMA_REGS_LBA_LOW; | 
 | 359 | 	buf[i++] = qc->tf.lbam; | 
 | 360 | 	buf[i++] = ADMA_REGS_LBA_MID; | 
 | 361 | 	buf[i++] = qc->tf.lbah; | 
 | 362 | 	buf[i++] = ADMA_REGS_LBA_HIGH; | 
 | 363 | 	buf[i++] = 0; | 
 | 364 | 	buf[i++] = ADMA_REGS_CONTROL; | 
 | 365 | 	buf[i++] = rIGN; | 
 | 366 | 	buf[i++] = 0; | 
 | 367 | 	buf[i++] = qc->tf.command; | 
 | 368 | 	buf[i++] = ADMA_REGS_COMMAND | rEND; | 
 | 369 |  | 
 | 370 | 	buf[3] = (i >> 3) - 2;				/* cLEN */ | 
 | 371 | 	*(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i);	/* cPRD */ | 
 | 372 |  | 
 | 373 | 	i = adma_fill_sg(qc); | 
 | 374 | 	wmb();	/* flush PRDs and pkt to memory */ | 
 | 375 | #if 0 | 
 | 376 | 	/* dump out CPB + PRDs for debug */ | 
 | 377 | 	{ | 
 | 378 | 		int j, len = 0; | 
 | 379 | 		static char obuf[2048]; | 
 | 380 | 		for (j = 0; j < i; ++j) { | 
 | 381 | 			len += sprintf(obuf+len, "%02x ", buf[j]); | 
 | 382 | 			if ((j & 7) == 7) { | 
 | 383 | 				printk("%s\n", obuf); | 
 | 384 | 				len = 0; | 
 | 385 | 			} | 
 | 386 | 		} | 
 | 387 | 		if (len) | 
 | 388 | 			printk("%s\n", obuf); | 
 | 389 | 	} | 
 | 390 | #endif | 
 | 391 | } | 
 | 392 |  | 
 | 393 | static inline void adma_packet_start(struct ata_queued_cmd *qc) | 
 | 394 | { | 
 | 395 | 	struct ata_port *ap = qc->ap; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 396 | 	void __iomem *chan = ADMA_PORT_REGS(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 397 |  | 
 | 398 | 	VPRINTK("ENTER, ap %p\n", ap); | 
 | 399 |  | 
 | 400 | 	/* fire up the ADMA engine */ | 
| Jeff Garzik | 68399bb | 2005-10-11 01:44:14 -0400 | [diff] [blame] | 401 | 	writew(aPIOMD4 | aGO, chan + ADMA_CONTROL); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 402 | } | 
 | 403 |  | 
| Tejun Heo | 9a3d9eb | 2006-01-23 13:09:36 +0900 | [diff] [blame] | 404 | static unsigned int adma_qc_issue(struct ata_queued_cmd *qc) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 405 | { | 
 | 406 | 	struct adma_port_priv *pp = qc->ap->private_data; | 
 | 407 |  | 
 | 408 | 	switch (qc->tf.protocol) { | 
 | 409 | 	case ATA_PROT_DMA: | 
 | 410 | 		pp->state = adma_state_pkt; | 
 | 411 | 		adma_packet_start(qc); | 
 | 412 | 		return 0; | 
 | 413 |  | 
| Tejun Heo | 0dc3688 | 2007-12-18 16:34:43 -0500 | [diff] [blame] | 414 | 	case ATAPI_PROT_DMA: | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 415 | 		BUG(); | 
 | 416 | 		break; | 
 | 417 |  | 
 | 418 | 	default: | 
 | 419 | 		break; | 
 | 420 | 	} | 
 | 421 |  | 
 | 422 | 	pp->state = adma_state_mmio; | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 423 | 	return ata_sff_qc_issue(qc); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 424 | } | 
 | 425 |  | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 426 | static inline unsigned int adma_intr_pkt(struct ata_host *host) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 427 | { | 
 | 428 | 	unsigned int handled = 0, port_no; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 429 |  | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 430 | 	for (port_no = 0; port_no < host->n_ports; ++port_no) { | 
 | 431 | 		struct ata_port *ap = host->ports[port_no]; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 432 | 		struct adma_port_priv *pp; | 
 | 433 | 		struct ata_queued_cmd *qc; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 434 | 		void __iomem *chan = ADMA_PORT_REGS(ap); | 
| Jeff Garzik | a7dac44 | 2005-10-30 04:44:42 -0500 | [diff] [blame] | 435 | 		u8 status = readb(chan + ADMA_STATUS); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 436 |  | 
 | 437 | 		if (status == 0) | 
 | 438 | 			continue; | 
 | 439 | 		handled = 1; | 
 | 440 | 		adma_enter_reg_mode(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 441 | 		pp = ap->private_data; | 
 | 442 | 		if (!pp || pp->state != adma_state_pkt) | 
 | 443 | 			continue; | 
| Tejun Heo | 9af5c9c | 2007-08-06 18:36:22 +0900 | [diff] [blame] | 444 | 		qc = ata_qc_from_tag(ap, ap->link.active_tag); | 
| Jeff Garzik | 94ec1ef | 2005-10-30 02:15:08 -0500 | [diff] [blame] | 445 | 		if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 446 | 			if (status & aPERR) | 
 | 447 | 				qc->err_mask |= AC_ERR_HOST_BUS; | 
 | 448 | 			else if ((status & (aPSD | aUIRQ))) | 
| Albert Lee | a22e2eb | 2005-12-05 15:38:02 +0800 | [diff] [blame] | 449 | 				qc->err_mask |= AC_ERR_OTHER; | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 450 |  | 
 | 451 | 			if (pp->pkt[0] & cATERR) | 
 | 452 | 				qc->err_mask |= AC_ERR_DEV; | 
| Jeff Garzik | a21a84a | 2005-10-28 15:43:16 -0400 | [diff] [blame] | 453 | 			else if (pp->pkt[0] != cDONE) | 
| Albert Lee | a22e2eb | 2005-12-05 15:38:02 +0800 | [diff] [blame] | 454 | 				qc->err_mask |= AC_ERR_OTHER; | 
| Jeff Garzik | a7dac44 | 2005-10-30 04:44:42 -0500 | [diff] [blame] | 455 |  | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 456 | 			if (!qc->err_mask) | 
 | 457 | 				ata_qc_complete(qc); | 
 | 458 | 			else { | 
| Tejun Heo | 9af5c9c | 2007-08-06 18:36:22 +0900 | [diff] [blame] | 459 | 				struct ata_eh_info *ehi = &ap->link.eh_info; | 
| Jeff Garzik | 640fdb5 | 2007-08-03 11:10:07 -0400 | [diff] [blame] | 460 | 				ata_ehi_clear_desc(ehi); | 
 | 461 | 				ata_ehi_push_desc(ehi, | 
 | 462 | 					"ADMA-status 0x%02X", status); | 
 | 463 | 				ata_ehi_push_desc(ehi, | 
 | 464 | 					"pkt[0] 0x%02X", pp->pkt[0]); | 
 | 465 |  | 
 | 466 | 				if (qc->err_mask == AC_ERR_DEV) | 
 | 467 | 					ata_port_abort(ap); | 
 | 468 | 				else | 
 | 469 | 					ata_port_freeze(ap); | 
 | 470 | 			} | 
| Jeff Garzik | a21a84a | 2005-10-28 15:43:16 -0400 | [diff] [blame] | 471 | 		} | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 472 | 	} | 
 | 473 | 	return handled; | 
 | 474 | } | 
 | 475 |  | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 476 | static inline unsigned int adma_intr_mmio(struct ata_host *host) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 477 | { | 
 | 478 | 	unsigned int handled = 0, port_no; | 
 | 479 |  | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 480 | 	for (port_no = 0; port_no < host->n_ports; ++port_no) { | 
| Tejun Heo | 3e4ec34 | 2010-05-10 21:41:30 +0200 | [diff] [blame] | 481 | 		struct ata_port *ap = host->ports[port_no]; | 
 | 482 | 		struct adma_port_priv *pp = ap->private_data; | 
 | 483 | 		struct ata_queued_cmd *qc; | 
 | 484 |  | 
 | 485 | 		if (!pp || pp->state != adma_state_mmio) | 
 | 486 | 			continue; | 
 | 487 | 		qc = ata_qc_from_tag(ap, ap->link.active_tag); | 
 | 488 | 		if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { | 
 | 489 |  | 
 | 490 | 			/* check main status, clearing INTRQ */ | 
 | 491 | 			u8 status = ata_sff_check_status(ap); | 
 | 492 | 			if ((status & ATA_BUSY)) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 493 | 				continue; | 
| Tejun Heo | 3e4ec34 | 2010-05-10 21:41:30 +0200 | [diff] [blame] | 494 | 			DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", | 
 | 495 | 				ap->print_id, qc->tf.protocol, status); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 496 |  | 
| Tejun Heo | 3e4ec34 | 2010-05-10 21:41:30 +0200 | [diff] [blame] | 497 | 			/* complete taskfile transaction */ | 
 | 498 | 			pp->state = adma_state_idle; | 
 | 499 | 			qc->err_mask |= ac_err_mask(status); | 
 | 500 | 			if (!qc->err_mask) | 
 | 501 | 				ata_qc_complete(qc); | 
 | 502 | 			else { | 
 | 503 | 				struct ata_eh_info *ehi = &ap->link.eh_info; | 
 | 504 | 				ata_ehi_clear_desc(ehi); | 
 | 505 | 				ata_ehi_push_desc(ehi, "status 0x%02X", status); | 
| Jeff Garzik | 9bec2e3 | 2006-08-31 00:02:15 -0400 | [diff] [blame] | 506 |  | 
| Tejun Heo | 3e4ec34 | 2010-05-10 21:41:30 +0200 | [diff] [blame] | 507 | 				if (qc->err_mask == AC_ERR_DEV) | 
 | 508 | 					ata_port_abort(ap); | 
 | 509 | 				else | 
 | 510 | 					ata_port_freeze(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 511 | 			} | 
| Tejun Heo | 3e4ec34 | 2010-05-10 21:41:30 +0200 | [diff] [blame] | 512 | 			handled = 1; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 513 | 		} | 
 | 514 | 	} | 
 | 515 | 	return handled; | 
 | 516 | } | 
 | 517 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 518 | static irqreturn_t adma_intr(int irq, void *dev_instance) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 519 | { | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 520 | 	struct ata_host *host = dev_instance; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 521 | 	unsigned int handled = 0; | 
 | 522 |  | 
 | 523 | 	VPRINTK("ENTER\n"); | 
 | 524 |  | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 525 | 	spin_lock(&host->lock); | 
 | 526 | 	handled  = adma_intr_pkt(host) | adma_intr_mmio(host); | 
 | 527 | 	spin_unlock(&host->lock); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 528 |  | 
 | 529 | 	VPRINTK("EXIT\n"); | 
 | 530 |  | 
 | 531 | 	return IRQ_RETVAL(handled); | 
 | 532 | } | 
 | 533 |  | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 534 | static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 535 | { | 
 | 536 | 	port->cmd_addr		= | 
 | 537 | 	port->data_addr		= base + 0x000; | 
 | 538 | 	port->error_addr	= | 
 | 539 | 	port->feature_addr	= base + 0x004; | 
 | 540 | 	port->nsect_addr	= base + 0x008; | 
 | 541 | 	port->lbal_addr		= base + 0x00c; | 
 | 542 | 	port->lbam_addr		= base + 0x010; | 
 | 543 | 	port->lbah_addr		= base + 0x014; | 
 | 544 | 	port->device_addr	= base + 0x018; | 
 | 545 | 	port->status_addr	= | 
 | 546 | 	port->command_addr	= base + 0x01c; | 
 | 547 | 	port->altstatus_addr	= | 
 | 548 | 	port->ctl_addr		= base + 0x038; | 
 | 549 | } | 
 | 550 |  | 
 | 551 | static int adma_port_start(struct ata_port *ap) | 
 | 552 | { | 
| Jeff Garzik | cca3974 | 2006-08-24 03:19:22 -0400 | [diff] [blame] | 553 | 	struct device *dev = ap->host->dev; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 554 | 	struct adma_port_priv *pp; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 555 |  | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 556 | 	adma_enter_reg_mode(ap); | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 557 | 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 558 | 	if (!pp) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 559 | 		return -ENOMEM; | 
 | 560 | 	pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, | 
 | 561 | 				      GFP_KERNEL); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 562 | 	if (!pp->pkt) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 563 | 		return -ENOMEM; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 564 | 	/* paranoia? */ | 
 | 565 | 	if ((pp->pkt_dma & 7) != 0) { | 
| Jeff Garzik | 5796d1c | 2007-10-26 00:03:37 -0400 | [diff] [blame] | 566 | 		printk(KERN_ERR "bad alignment for pp->pkt_dma: %08x\n", | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 567 | 						(u32)pp->pkt_dma); | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 568 | 		return -ENOMEM; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 569 | 	} | 
 | 570 | 	memset(pp->pkt, 0, ADMA_PKT_BYTES); | 
 | 571 | 	ap->private_data = pp; | 
 | 572 | 	adma_reinit_engine(ap); | 
 | 573 | 	return 0; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 574 | } | 
 | 575 |  | 
 | 576 | static void adma_port_stop(struct ata_port *ap) | 
 | 577 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 578 | 	adma_reset_engine(ap); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 579 | } | 
 | 580 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 581 | static void adma_host_init(struct ata_host *host, unsigned int chip_id) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 582 | { | 
 | 583 | 	unsigned int port_no; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 584 |  | 
 | 585 | 	/* enable/lock aGO operation */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 586 | 	writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 587 |  | 
 | 588 | 	/* reset the ADMA logic */ | 
 | 589 | 	for (port_no = 0; port_no < ADMA_PORTS; ++port_no) | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 590 | 		adma_reset_engine(host->ports[port_no]); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 591 | } | 
 | 592 |  | 
 | 593 | static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) | 
 | 594 | { | 
 | 595 | 	int rc; | 
 | 596 |  | 
| Yang Hongyang | 284901a | 2009-04-06 19:01:15 -0700 | [diff] [blame] | 597 | 	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 598 | 	if (rc) { | 
| Joe Perches | a44fec1 | 2011-04-15 15:51:58 -0700 | [diff] [blame] | 599 | 		dev_err(&pdev->dev, "32-bit DMA enable failed\n"); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 600 | 		return rc; | 
 | 601 | 	} | 
| Yang Hongyang | 284901a | 2009-04-06 19:01:15 -0700 | [diff] [blame] | 602 | 	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 603 | 	if (rc) { | 
| Joe Perches | a44fec1 | 2011-04-15 15:51:58 -0700 | [diff] [blame] | 604 | 		dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n"); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 605 | 		return rc; | 
 | 606 | 	} | 
 | 607 | 	return 0; | 
 | 608 | } | 
 | 609 |  | 
 | 610 | static int adma_ata_init_one(struct pci_dev *pdev, | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 611 | 			     const struct pci_device_id *ent) | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 612 | { | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 613 | 	unsigned int board_idx = (unsigned int) ent->driver_data; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 614 | 	const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL }; | 
 | 615 | 	struct ata_host *host; | 
 | 616 | 	void __iomem *mmio_base; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 617 | 	int rc, port_no; | 
 | 618 |  | 
| Joe Perches | 06296a1 | 2011-04-15 15:52:00 -0700 | [diff] [blame] | 619 | 	ata_print_version_once(&pdev->dev, DRV_VERSION); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 620 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 621 | 	/* alloc host */ | 
 | 622 | 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS); | 
 | 623 | 	if (!host) | 
 | 624 | 		return -ENOMEM; | 
 | 625 |  | 
 | 626 | 	/* acquire resources and fill host */ | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 627 | 	rc = pcim_enable_device(pdev); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 628 | 	if (rc) | 
 | 629 | 		return rc; | 
 | 630 |  | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 631 | 	if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) | 
 | 632 | 		return -ENODEV; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 633 |  | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 634 | 	rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME); | 
 | 635 | 	if (rc) | 
 | 636 | 		return rc; | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 637 | 	host->iomap = pcim_iomap_table(pdev); | 
 | 638 | 	mmio_base = host->iomap[ADMA_MMIO_BAR]; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 639 |  | 
 | 640 | 	rc = adma_set_dma_masks(pdev, mmio_base); | 
 | 641 | 	if (rc) | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 642 | 		return rc; | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 643 |  | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 644 | 	for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { | 
 | 645 | 		struct ata_port *ap = host->ports[port_no]; | 
 | 646 | 		void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no); | 
 | 647 | 		unsigned int offset = port_base - mmio_base; | 
 | 648 |  | 
 | 649 | 		adma_ata_setup_port(&ap->ioaddr, port_base); | 
 | 650 |  | 
 | 651 | 		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio"); | 
 | 652 | 		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port"); | 
 | 653 | 	} | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 654 |  | 
 | 655 | 	/* initialize adapter */ | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 656 | 	adma_host_init(host, board_idx); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 657 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 658 | 	pci_set_master(pdev); | 
 | 659 | 	return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED, | 
 | 660 | 				 &adma_ata_sht); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 661 | } | 
 | 662 |  | 
 | 663 | static int __init adma_ata_init(void) | 
 | 664 | { | 
| Pavel Roskin | b788719 | 2006-08-10 18:13:18 +0900 | [diff] [blame] | 665 | 	return pci_register_driver(&adma_ata_pci_driver); | 
| Mark Lord | edea3ab | 2005-10-10 17:53:58 -0400 | [diff] [blame] | 666 | } | 
 | 667 |  | 
 | 668 | static void __exit adma_ata_exit(void) | 
 | 669 | { | 
 | 670 | 	pci_unregister_driver(&adma_ata_pci_driver); | 
 | 671 | } | 
 | 672 |  | 
 | 673 | MODULE_AUTHOR("Mark Lord"); | 
 | 674 | MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver"); | 
 | 675 | MODULE_LICENSE("GPL"); | 
 | 676 | MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl); | 
 | 677 | MODULE_VERSION(DRV_VERSION); | 
 | 678 |  | 
 | 679 | module_init(adma_ata_init); | 
 | 680 | module_exit(adma_ata_exit); |