pdc_adma.c 18.2 KB
Newer Older
1 2 3 4 5 6 7
/*
 *  pdc_adma.c - Pacific Digital Corporation ADMA
 *
 *  Maintained by:  Mark Lord <mlord@pobox.com>
 *
 *  Copyright 2005 Mark Lord
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *  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.
 *
 *  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; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 *  libata documentation is available via 'make {ps|pdf}docs',
 *  as Documentation/DocBook/libata.*
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *
 *
 *  Supports ATA disks in single-packet ADMA mode.
 *  Uses PIO for everything else.
 *
 *  TODO:  Use ADMA transfers for ATAPI devices, when possible.
 *  This requires careful attention to a number of quirks of the chip.
 *
 */

#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>
42
#include <linux/device.h>
43 44 45 46
#include <scsi/scsi_host.h>
#include <linux/libata.h>

#define DRV_NAME	"pdc_adma"
Jeff Garzik's avatar
Jeff Garzik committed
47
#define DRV_VERSION	"1.0"
48 49

/* macro to calculate base address for ATA regs */
50
#define ADMA_ATA_REGS(base, port_no)	((base) + ((port_no) * 0x40))
51 52

/* macro to calculate base address for ADMA regs */
53
#define ADMA_REGS(base, port_no)	((base) + 0x80 + ((port_no) * 0x20))
Tejun Heo's avatar
Tejun Heo committed
54

55 56 57
/* macro to obtain addresses from ata_port */
#define ADMA_PORT_REGS(ap) \
	ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no)
58 59

enum {
Tejun Heo's avatar
Tejun Heo committed
60 61
	ADMA_MMIO_BAR		= 4,

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
	ADMA_PORTS		= 2,
	ADMA_CPB_BYTES		= 40,
	ADMA_PRD_BYTES		= LIBATA_MAX_PRD * 16,
	ADMA_PKT_BYTES		= ADMA_CPB_BYTES + ADMA_PRD_BYTES,

	ADMA_DMA_BOUNDARY	= 0xffffffff,

	/* global register offsets */
	ADMA_MODE_LOCK		= 0x00c7,

	/* per-channel register offsets */
	ADMA_CONTROL		= 0x0000, /* ADMA control */
	ADMA_STATUS		= 0x0002, /* ADMA status */
	ADMA_CPB_COUNT		= 0x0004, /* CPB count */
	ADMA_CPB_CURRENT	= 0x000c, /* current CPB address */
	ADMA_CPB_NEXT		= 0x000c, /* next CPB address */
	ADMA_CPB_LOOKUP		= 0x0010, /* CPB lookup table */
	ADMA_FIFO_IN		= 0x0014, /* input FIFO threshold */
	ADMA_FIFO_OUT		= 0x0016, /* output FIFO threshold */

	/* ADMA_CONTROL register bits */
	aNIEN			= (1 << 8), /* irq mask: 1==masked */
	aGO			= (1 << 7), /* packet trigger ("Go!") */
	aRSTADM			= (1 << 5), /* ADMA logic reset */
	aPIOMD4			= 0x0003,   /* PIO mode 4 */

	/* ADMA_STATUS register bits */
	aPSD			= (1 << 6),
	aUIRQ			= (1 << 4),
	aPERR			= (1 << 0),

	/* CPB bits */
	cDONE			= (1 << 0),
95 96
	cATERR			= (1 << 3),

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	cVLD			= (1 << 0),
	cDAT			= (1 << 2),
	cIEN			= (1 << 3),

	/* PRD bits */
	pORD			= (1 << 4),
	pDIRO			= (1 << 5),
	pEND			= (1 << 7),

	/* ATA register flags */
	rIGN			= (1 << 5),
	rEND			= (1 << 7),

	/* ATA register addresses */
	ADMA_REGS_CONTROL	= 0x0e,
	ADMA_REGS_SECTOR_COUNT	= 0x12,
	ADMA_REGS_LBA_LOW	= 0x13,
	ADMA_REGS_LBA_MID	= 0x14,
	ADMA_REGS_LBA_HIGH	= 0x15,
	ADMA_REGS_DEVICE	= 0x16,
	ADMA_REGS_COMMAND	= 0x17,

	/* PCI device IDs */
	board_1841_idx		= 0,	/* ADMA 2-port controller */
};

typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t;

struct adma_port_priv {
	u8			*pkt;
	dma_addr_t		pkt_dma;
	adma_state_t		state;
};

131
static int adma_ata_init_one(struct pci_dev *pdev,
132 133
				const struct pci_device_id *ent);
static int adma_port_start(struct ata_port *ap);
Jeff Garzik's avatar
Jeff Garzik committed
134
static void adma_host_stop(struct ata_host *host);
135 136
static void adma_port_stop(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
137
static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
138 139 140 141
static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void adma_bmdma_stop(struct ata_queued_cmd *qc);
static u8 adma_bmdma_status(struct ata_port *ap);
static void adma_irq_clear(struct ata_port *ap);
142 143 144
static void adma_freeze(struct ata_port *ap);
static void adma_thaw(struct ata_port *ap);
static void adma_error_handler(struct ata_port *ap);
145

146
static struct scsi_host_template adma_ata_sht = {
147 148 149 150
	.module			= THIS_MODULE,
	.name			= DRV_NAME,
	.ioctl			= ata_scsi_ioctl,
	.queuecommand		= ata_scsi_queuecmd,
151 152 153 154
	.slave_configure	= ata_scsi_slave_config,
	.slave_destroy		= ata_scsi_slave_destroy,
	.bios_param		= ata_std_bios_param,
	.proc_name		= DRV_NAME,
155 156 157
	.can_queue		= ATA_DEF_QUEUE,
	.this_id		= ATA_SHT_THIS_ID,
	.sg_tablesize		= LIBATA_MAX_PRD,
158
	.dma_boundary		= ADMA_DMA_BOUNDARY,
159 160
	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
	.use_clustering		= ENABLE_CLUSTERING,
161
	.emulated		= ATA_SHT_EMULATED,
162 163
};

164
static const struct ata_port_operations adma_ata_ops = {
165 166 167
	.tf_load		= ata_tf_load,
	.tf_read		= ata_tf_read,
	.exec_command		= ata_exec_command,
168
	.check_status		= ata_check_status,
169
	.dev_select		= ata_std_dev_select,
170 171
	.check_atapi_dma	= adma_check_atapi_dma,
	.data_xfer		= ata_data_xfer,
172 173
	.qc_prep		= adma_qc_prep,
	.qc_issue		= adma_qc_issue,
174 175 176
	.freeze			= adma_freeze,
	.thaw			= adma_thaw,
	.error_handler		= adma_error_handler,
177
	.irq_clear		= adma_irq_clear,
178
	.irq_on			= ata_irq_on,
179 180 181 182 183 184 185 186 187 188
	.port_start		= adma_port_start,
	.port_stop		= adma_port_stop,
	.host_stop		= adma_host_stop,
	.bmdma_stop		= adma_bmdma_stop,
	.bmdma_status		= adma_bmdma_status,
};

static struct ata_port_info adma_port_info[] = {
	/* board_1841_idx */
	{
189
		.flags		= ATA_FLAG_SLAVE_POSS |
190 191
				  ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
				  ATA_FLAG_PIO_POLLING,
192
		.pio_mask	= 0x10, /* pio4 */
193
		.udma_mask	= ATA_UDMA4,
194 195 196 197
		.port_ops	= &adma_ata_ops,
	},
};

198
static const struct pci_device_id adma_ata_pci_tbl[] = {
199
	{ PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

	{ }	/* terminate list */
};

static struct pci_driver adma_ata_pci_driver = {
	.name			= DRV_NAME,
	.id_table		= adma_ata_pci_tbl,
	.probe			= adma_ata_init_one,
	.remove			= ata_pci_remove_one,
};

static int adma_check_atapi_dma(struct ata_queued_cmd *qc)
{
	return 1;	/* ATAPI DMA not yet supported */
}

static void adma_bmdma_stop(struct ata_queued_cmd *qc)
{
	/* nothing */
}

static u8 adma_bmdma_status(struct ata_port *ap)
{
	return 0;
}

static void adma_irq_clear(struct ata_port *ap)
{
	/* nothing */
}

231
static void adma_reset_engine(struct ata_port *ap)
232
{
233 234
	void __iomem *chan = ADMA_PORT_REGS(ap);

235 236 237 238 239 240 241 242 243 244
	/* reset ADMA to idle state */
	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
	udelay(2);
	writew(aPIOMD4, chan + ADMA_CONTROL);
	udelay(2);
}

static void adma_reinit_engine(struct ata_port *ap)
{
	struct adma_port_priv *pp = ap->private_data;
245
	void __iomem *chan = ADMA_PORT_REGS(ap);
246 247

	/* mask/clear ATA interrupts */
Tejun Heo's avatar
Tejun Heo committed
248
	writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
249 250 251
	ata_check_status(ap);

	/* reset the ADMA engine */
252
	adma_reset_engine(ap);
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271

	/* set in-FIFO threshold to 0x100 */
	writew(0x100, chan + ADMA_FIFO_IN);

	/* set CPB pointer */
	writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT);

	/* set out-FIFO threshold to 0x100 */
	writew(0x100, chan + ADMA_FIFO_OUT);

	/* set CPB count */
	writew(1, chan + ADMA_CPB_COUNT);

	/* read/discard ADMA status */
	readb(chan + ADMA_STATUS);
}

static inline void adma_enter_reg_mode(struct ata_port *ap)
{
272
	void __iomem *chan = ADMA_PORT_REGS(ap);
273 274 275 276 277

	writew(aPIOMD4, chan + ADMA_CONTROL);
	readb(chan + ADMA_STATUS);	/* flush */
}

278
static void adma_freeze(struct ata_port *ap)
279
{
280 281 282 283 284 285 286 287 288 289 290 291
	void __iomem *chan = ADMA_PORT_REGS(ap);

	/* mask/clear ATA interrupts */
	writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
	ata_check_status(ap);

	/* reset ADMA to idle state */
	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
	udelay(2);
	writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
	udelay(2);
}
292

293 294
static void adma_thaw(struct ata_port *ap)
{
295 296 297
	adma_reinit_engine(ap);
}

298
static int adma_prereset(struct ata_link *link, unsigned long deadline)
299
{
300
	struct ata_port *ap = link->ap;
301 302 303 304 305
	struct adma_port_priv *pp = ap->private_data;

	if (pp->state != adma_state_idle) /* healthy paranoia */
		pp->state = adma_state_mmio;
	adma_reinit_engine(ap);
306

307
	return ata_std_prereset(link, deadline);
308 309 310 311 312 313
}

static void adma_error_handler(struct ata_port *ap)
{
	ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
		  ata_std_postreset);
314 315 316 317
}

static int adma_fill_sg(struct ata_queued_cmd *qc)
{
318
	struct scatterlist *sg;
319 320
	struct ata_port *ap = qc->ap;
	struct adma_port_priv *pp = ap->private_data;
Jeff Garzik's avatar
Jeff Garzik committed
321
	u8  *buf = pp->pkt, *last_buf = NULL;
322
	int i = (2 + buf[3]) * 8;
323 324
	u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);

325
	ata_for_each_sg(sg, qc) {
326 327 328 329 330 331 332 333 334 335 336
		u32 addr;
		u32 len;

		addr = (u32)sg_dma_address(sg);
		*(__le32 *)(buf + i) = cpu_to_le32(addr);
		i += 4;

		len = sg_dma_len(sg) >> 3;
		*(__le32 *)(buf + i) = cpu_to_le32(len);
		i += 4;

Jeff Garzik's avatar
Jeff Garzik committed
337
		last_buf = &buf[i];
338 339 340 341 342
		buf[i++] = pFLAGS;
		buf[i++] = qc->dev->dma_mode & 0xf;
		buf[i++] = 0;	/* pPKLW */
		buf[i++] = 0;	/* reserved */

343 344
		*(__le32 *)(buf + i) =
			(pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
345 346
		i += 4;

347
		VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
348 349
					(unsigned long)addr, len);
	}
Jeff Garzik's avatar
Jeff Garzik committed
350 351 352 353

	if (likely(last_buf))
		*last_buf |= pEND;

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	return i;
}

static void adma_qc_prep(struct ata_queued_cmd *qc)
{
	struct adma_port_priv *pp = qc->ap->private_data;
	u8  *buf = pp->pkt;
	u32 pkt_dma = (u32)pp->pkt_dma;
	int i = 0;

	VPRINTK("ENTER\n");

	adma_enter_reg_mode(qc->ap);
	if (qc->tf.protocol != ATA_PROT_DMA) {
		ata_qc_prep(qc);
		return;
	}

	buf[i++] = 0;	/* Response flags */
	buf[i++] = 0;	/* reserved */
	buf[i++] = cVLD | cDAT | cIEN;
	i++;		/* cLEN, gets filled in below */

	*(__le32 *)(buf+i) = cpu_to_le32(pkt_dma);	/* cNCPB */
	i += 4;		/* cNCPB */
	i += 4;		/* cPRD, gets filled in below */

	buf[i++] = 0;	/* reserved */
	buf[i++] = 0;	/* reserved */
	buf[i++] = 0;	/* reserved */
	buf[i++] = 0;	/* reserved */

	/* ATA registers; must be a multiple of 4 */
	buf[i++] = qc->tf.device;
	buf[i++] = ADMA_REGS_DEVICE;
	if ((qc->tf.flags & ATA_TFLAG_LBA48)) {
		buf[i++] = qc->tf.hob_nsect;
		buf[i++] = ADMA_REGS_SECTOR_COUNT;
		buf[i++] = qc->tf.hob_lbal;
		buf[i++] = ADMA_REGS_LBA_LOW;
		buf[i++] = qc->tf.hob_lbam;
		buf[i++] = ADMA_REGS_LBA_MID;
		buf[i++] = qc->tf.hob_lbah;
		buf[i++] = ADMA_REGS_LBA_HIGH;
	}
	buf[i++] = qc->tf.nsect;
	buf[i++] = ADMA_REGS_SECTOR_COUNT;
	buf[i++] = qc->tf.lbal;
	buf[i++] = ADMA_REGS_LBA_LOW;
	buf[i++] = qc->tf.lbam;
	buf[i++] = ADMA_REGS_LBA_MID;
	buf[i++] = qc->tf.lbah;
	buf[i++] = ADMA_REGS_LBA_HIGH;
	buf[i++] = 0;
	buf[i++] = ADMA_REGS_CONTROL;
	buf[i++] = rIGN;
	buf[i++] = 0;
	buf[i++] = qc->tf.command;
	buf[i++] = ADMA_REGS_COMMAND | rEND;

	buf[3] = (i >> 3) - 2;				/* cLEN */
	*(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i);	/* cPRD */

	i = adma_fill_sg(qc);
	wmb();	/* flush PRDs and pkt to memory */
#if 0
	/* dump out CPB + PRDs for debug */
	{
		int j, len = 0;
		static char obuf[2048];
		for (j = 0; j < i; ++j) {
			len += sprintf(obuf+len, "%02x ", buf[j]);
			if ((j & 7) == 7) {
				printk("%s\n", obuf);
				len = 0;
			}
		}
		if (len)
			printk("%s\n", obuf);
	}
#endif
}

static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
440
	void __iomem *chan = ADMA_PORT_REGS(ap);
441 442 443 444

	VPRINTK("ENTER, ap %p\n", ap);

	/* fire up the ADMA engine */
445
	writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
446 447
}

448
static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
{
	struct adma_port_priv *pp = qc->ap->private_data;

	switch (qc->tf.protocol) {
	case ATA_PROT_DMA:
		pp->state = adma_state_pkt;
		adma_packet_start(qc);
		return 0;

	case ATA_PROT_ATAPI_DMA:
		BUG();
		break;

	default:
		break;
	}

	pp->state = adma_state_mmio;
	return ata_qc_issue_prot(qc);
}

Jeff Garzik's avatar
Jeff Garzik committed
470
static inline unsigned int adma_intr_pkt(struct ata_host *host)
471 472 473
{
	unsigned int handled = 0, port_no;

Jeff Garzik's avatar
Jeff Garzik committed
474 475
	for (port_no = 0; port_no < host->n_ports; ++port_no) {
		struct ata_port *ap = host->ports[port_no];
476 477
		struct adma_port_priv *pp;
		struct ata_queued_cmd *qc;
478
		void __iomem *chan = ADMA_PORT_REGS(ap);
479
		u8 status = readb(chan + ADMA_STATUS);
480 481 482 483 484

		if (status == 0)
			continue;
		handled = 1;
		adma_enter_reg_mode(ap);
Jeff Garzik's avatar
Jeff Garzik committed
485
		if (ap->flags & ATA_FLAG_DISABLED)
486 487 488 489
			continue;
		pp = ap->private_data;
		if (!pp || pp->state != adma_state_pkt)
			continue;
Tejun Heo's avatar
Tejun Heo committed
490
		qc = ata_qc_from_tag(ap, ap->link.active_tag);
491
		if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
492 493 494
			if (status & aPERR)
				qc->err_mask |= AC_ERR_HOST_BUS;
			else if ((status & (aPSD | aUIRQ)))
495
				qc->err_mask |= AC_ERR_OTHER;
496 497 498

			if (pp->pkt[0] & cATERR)
				qc->err_mask |= AC_ERR_DEV;
499
			else if (pp->pkt[0] != cDONE)
500
				qc->err_mask |= AC_ERR_OTHER;
501

502 503 504
			if (!qc->err_mask)
				ata_qc_complete(qc);
			else {
Tejun Heo's avatar
Tejun Heo committed
505
				struct ata_eh_info *ehi = &ap->link.eh_info;
506 507 508 509 510 511 512 513 514 515 516
				ata_ehi_clear_desc(ehi);
				ata_ehi_push_desc(ehi,
					"ADMA-status 0x%02X", status);
				ata_ehi_push_desc(ehi,
					"pkt[0] 0x%02X", pp->pkt[0]);

				if (qc->err_mask == AC_ERR_DEV)
					ata_port_abort(ap);
				else
					ata_port_freeze(ap);
			}
517
		}
518 519 520 521
	}
	return handled;
}

Jeff Garzik's avatar
Jeff Garzik committed
522
static inline unsigned int adma_intr_mmio(struct ata_host *host)
523 524 525
{
	unsigned int handled = 0, port_no;

Jeff Garzik's avatar
Jeff Garzik committed
526
	for (port_no = 0; port_no < host->n_ports; ++port_no) {
527
		struct ata_port *ap;
Jeff Garzik's avatar
Jeff Garzik committed
528
		ap = host->ports[port_no];
Jeff Garzik's avatar
Jeff Garzik committed
529
		if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
530 531 532 533
			struct ata_queued_cmd *qc;
			struct adma_port_priv *pp = ap->private_data;
			if (!pp || pp->state != adma_state_mmio)
				continue;
Tejun Heo's avatar
Tejun Heo committed
534
			qc = ata_qc_from_tag(ap, ap->link.active_tag);
535
			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
536 537

				/* check main status, clearing INTRQ */
538
				u8 status = ata_check_status(ap);
539 540 541
				if ((status & ATA_BUSY))
					continue;
				DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
Tejun Heo's avatar
Tejun Heo committed
542
					ap->print_id, qc->tf.protocol, status);
543

544 545
				/* complete taskfile transaction */
				pp->state = adma_state_idle;
546
				qc->err_mask |= ac_err_mask(status);
547 548 549
				if (!qc->err_mask)
					ata_qc_complete(qc);
				else {
Tejun Heo's avatar
Tejun Heo committed
550 551
					struct ata_eh_info *ehi =
						&ap->link.eh_info;
552 553 554 555 556 557 558 559 560
					ata_ehi_clear_desc(ehi);
					ata_ehi_push_desc(ehi,
						"status 0x%02X", status);

					if (qc->err_mask == AC_ERR_DEV)
						ata_port_abort(ap);
					else
						ata_port_freeze(ap);
				}
561 562 563 564 565 566 567
				handled = 1;
			}
		}
	}
	return handled;
}

568
static irqreturn_t adma_intr(int irq, void *dev_instance)
569
{
Jeff Garzik's avatar
Jeff Garzik committed
570
	struct ata_host *host = dev_instance;
571 572 573 574
	unsigned int handled = 0;

	VPRINTK("ENTER\n");

Jeff Garzik's avatar
Jeff Garzik committed
575 576 577
	spin_lock(&host->lock);
	handled  = adma_intr_pkt(host) | adma_intr_mmio(host);
	spin_unlock(&host->lock);
578 579 580 581 582 583

	VPRINTK("EXIT\n");

	return IRQ_RETVAL(handled);
}

Tejun Heo's avatar
Tejun Heo committed
584
static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base)
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
{
	port->cmd_addr		=
	port->data_addr		= base + 0x000;
	port->error_addr	=
	port->feature_addr	= base + 0x004;
	port->nsect_addr	= base + 0x008;
	port->lbal_addr		= base + 0x00c;
	port->lbam_addr		= base + 0x010;
	port->lbah_addr		= base + 0x014;
	port->device_addr	= base + 0x018;
	port->status_addr	=
	port->command_addr	= base + 0x01c;
	port->altstatus_addr	=
	port->ctl_addr		= base + 0x038;
}

static int adma_port_start(struct ata_port *ap)
{
Jeff Garzik's avatar
Jeff Garzik committed
603
	struct device *dev = ap->host->dev;
604 605 606 607 608 609 610
	struct adma_port_priv *pp;
	int rc;

	rc = ata_port_start(ap);
	if (rc)
		return rc;
	adma_enter_reg_mode(ap);
611
	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
612
	if (!pp)
613 614 615
		return -ENOMEM;
	pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
				      GFP_KERNEL);
616
	if (!pp->pkt)
617
		return -ENOMEM;
618 619
	/* paranoia? */
	if ((pp->pkt_dma & 7) != 0) {
620
		printk(KERN_ERR "bad alignment for pp->pkt_dma: %08x\n",
621
						(u32)pp->pkt_dma);
622
		return -ENOMEM;
623 624 625 626 627 628 629 630 631
	}
	memset(pp->pkt, 0, ADMA_PKT_BYTES);
	ap->private_data = pp;
	adma_reinit_engine(ap);
	return 0;
}

static void adma_port_stop(struct ata_port *ap)
{
632
	adma_reset_engine(ap);
633 634
}

Jeff Garzik's avatar
Jeff Garzik committed
635
static void adma_host_stop(struct ata_host *host)
636 637 638 639
{
	unsigned int port_no;

	for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
640
		adma_reset_engine(host->ports[port_no]);
641 642
}

643
static void adma_host_init(struct ata_host *host, unsigned int chip_id)
644 645 646 647
{
	unsigned int port_no;

	/* enable/lock aGO operation */
648
	writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK);
649 650 651

	/* reset the ADMA logic */
	for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
652
		adma_reset_engine(host->ports[port_no]);
653 654 655 656 657 658 659 660
}

static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
{
	int rc;

	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
	if (rc) {
661 662
		dev_printk(KERN_ERR, &pdev->dev,
			"32-bit DMA enable failed\n");
663 664 665 666
		return rc;
	}
	rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
	if (rc) {
667 668
		dev_printk(KERN_ERR, &pdev->dev,
			"32-bit consistent DMA enable failed\n");
669 670 671 672 673 674
		return rc;
	}
	return 0;
}

static int adma_ata_init_one(struct pci_dev *pdev,
Tejun Heo's avatar
Tejun Heo committed
675
			     const struct pci_device_id *ent)
676 677 678
{
	static int printed_version;
	unsigned int board_idx = (unsigned int) ent->driver_data;
679 680 681
	const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
	struct ata_host *host;
	void __iomem *mmio_base;
682 683 684
	int rc, port_no;

	if (!printed_version++)
685
		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
686

687 688 689 690 691 692
	/* alloc host */
	host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
	if (!host)
		return -ENOMEM;

	/* acquire resources and fill host */
693
	rc = pcim_enable_device(pdev);
694 695 696
	if (rc)
		return rc;

697 698
	if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0)
		return -ENODEV;
699

Tejun Heo's avatar
Tejun Heo committed
700 701 702
	rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
	if (rc)
		return rc;
703 704
	host->iomap = pcim_iomap_table(pdev);
	mmio_base = host->iomap[ADMA_MMIO_BAR];
705 706 707

	rc = adma_set_dma_masks(pdev, mmio_base);
	if (rc)
708
		return rc;
709

710 711 712 713 714 715 716 717 718 719
	for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
		struct ata_port *ap = host->ports[port_no];
		void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
		unsigned int offset = port_base - mmio_base;

		adma_ata_setup_port(&ap->ioaddr, port_base);

		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
	}
720 721

	/* initialize adapter */
722
	adma_host_init(host, board_idx);
723

724 725 726
	pci_set_master(pdev);
	return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED,
				 &adma_ata_sht);
727 728 729 730
}

static int __init adma_ata_init(void)
{
731
	return pci_register_driver(&adma_ata_pci_driver);
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
}

static void __exit adma_ata_exit(void)
{
	pci_unregister_driver(&adma_ata_pci_driver);
}

MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
MODULE_VERSION(DRV_VERSION);

module_init(adma_ata_init);
module_exit(adma_ata_exit);