setup-pci.c 17.2 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3 4
 *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
 *  Copyright (C) 1995-1998  Mark Lord
 *  Copyright (C)      2007  Bartlomiej Zolnierkiewicz
5
 *
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *  May be copied or modified under the terms of the GNU General Public License
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ide.h>
#include <linux/dma-mapping.h>

#include <asm/io.h>

/**
 *	ide_setup_pci_baseregs	-	place a PCI IDE controller native
 *	@dev: PCI device of interface to switch native
 *	@name: Name of interface
 *
 *	We attempt to place the PCI interface into PCI native mode. If
 *	we succeed the BARs are ok and the controller is in PCI mode.
26
 *	Returns 0 on success or an errno code.
L
Linus Torvalds 已提交
27 28 29 30
 *
 *	FIXME: if we program the interface and then fail to set the BARS
 *	we don't switch it back to legacy mode. Do we actually care ??
 */
31 32

static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name)
L
Linus Torvalds 已提交
33 34 35 36 37 38 39 40 41
{
	u8 progif = 0;

	/*
	 * Place both IDE interfaces into PCI "native" mode:
	 */
	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
			 (progif & 5) != 5) {
		if ((progif & 0xa) != 0xa) {
42 43
			printk(KERN_INFO "%s %s: device not capable of full "
				"native PCI mode\n", name, pci_name(dev));
L
Linus Torvalds 已提交
44 45
			return -EOPNOTSUPP;
		}
46 47
		printk(KERN_INFO "%s %s: placing both ports into native PCI "
			"mode\n", name, pci_name(dev));
L
Linus Torvalds 已提交
48 49 50
		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
		    (progif & 5) != 5) {
51 52 53
			printk(KERN_ERR "%s %s: rewrite of PROGIF failed, "
				"wanted 0x%04x, got 0x%04x\n",
				name, pci_name(dev), progif | 5, progif);
L
Linus Torvalds 已提交
54 55 56 57 58 59 60
			return -EOPNOTSUPP;
		}
	}
	return 0;
}

#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
61
static int ide_pci_clear_simplex(unsigned long dma_base, const char *name)
62 63 64 65 66
{
	u8 dma_stat = inb(dma_base + 2);

	outb(dma_stat & 0x60, dma_base + 2);
	dma_stat = inb(dma_base + 2);
67 68

	return (dma_stat & 0x80) ? 1 : 0;
69 70
}

L
Linus Torvalds 已提交
71
/**
72
 *	ide_pci_dma_base	-	setup BMIBA
73
 *	@hwif: IDE interface
74
 *	@d: IDE port info
L
Linus Torvalds 已提交
75
 *
76
 *	Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
L
Linus Torvalds 已提交
77 78
 */

79
unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d)
L
Linus Torvalds 已提交
80
{
81 82
	struct pci_dev *dev = to_pci_dev(hwif->dev);
	unsigned long dma_base = 0;
L
Linus Torvalds 已提交
83

84
	if (hwif->host_flags & IDE_HFLAG_MMIO)
L
Linus Torvalds 已提交
85 86 87 88 89
		return hwif->dma_base;

	if (hwif->mate && hwif->mate->dma_base) {
		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
	} else {
90 91 92 93
		u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4;

		dma_base = pci_resource_start(dev, baridx);

94
		if (dma_base == 0) {
95 96
			printk(KERN_ERR "%s %s: DMA base is invalid\n",
				d->name, pci_name(dev));
97 98
			return 0;
		}
L
Linus Torvalds 已提交
99 100
	}

101 102 103
	if (hwif->channel)
		dma_base += 8;

104 105 106 107 108 109
	return dma_base;
}
EXPORT_SYMBOL_GPL(ide_pci_dma_base);

int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d)
{
110
	struct pci_dev *dev = to_pci_dev(hwif->dev);
111 112 113
	u8 dma_stat;

	if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520))
114 115 116
		goto out;

	if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
117 118 119
		if (ide_pci_clear_simplex(hwif->dma_base, d->name))
			printk(KERN_INFO "%s %s: simplex device: DMA forced\n",
				d->name, pci_name(dev));
120 121 122 123 124 125 126 127 128 129 130 131 132
		goto out;
	}

	/*
	 * If the device claims "simplex" DMA, this means that only one of
	 * the two interfaces can be trusted with DMA at any point in time
	 * (so we should enable DMA only on one of the two interfaces).
	 *
	 * FIXME: At this point we haven't probed the drives so we can't make
	 * the appropriate decision.  Really we should defer this problem until
	 * we tune the drive then try to grab DMA ownership if we want to be
	 * the DMA end.  This has to be become dynamic to handle hot-plug.
	 */
133
	dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
134
	if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
135 136
		printk(KERN_INFO "%s %s: simplex device: DMA disabled\n",
			d->name, pci_name(dev));
137
		return -1;
L
Linus Torvalds 已提交
138
	}
139
out:
140
	return 0;
L
Linus Torvalds 已提交
141
}
142
EXPORT_SYMBOL_GPL(ide_pci_check_simplex);
143 144 145 146

/*
 * Set up BM-DMA capability (PnP BIOS should have done this)
 */
147
int ide_pci_set_master(struct pci_dev *dev, const char *name)
148 149 150 151 152 153 154 155 156 157
{
	u16 pcicmd;

	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);

	if ((pcicmd & PCI_COMMAND_MASTER) == 0) {
		pci_set_master(dev);

		if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) ||
		    (pcicmd & PCI_COMMAND_MASTER) == 0) {
158 159
			printk(KERN_ERR "%s %s: error updating PCICMD\n",
				name, pci_name(dev));
160 161 162 163 164 165
			return -EIO;
		}
	}

	return 0;
}
166
EXPORT_SYMBOL_GPL(ide_pci_set_master);
L
Linus Torvalds 已提交
167 168
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */

169
void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
L
Linus Torvalds 已提交
170
{
171 172 173
	printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n",
		d->name, pci_name(dev),
		dev->vendor, dev->device, dev->revision);
L
Linus Torvalds 已提交
174 175 176 177 178 179 180
}
EXPORT_SYMBOL_GPL(ide_setup_pci_noise);


/**
 *	ide_pci_enable	-	do PCI enables
 *	@dev: PCI device
181
 *	@d: IDE port info
L
Linus Torvalds 已提交
182 183
 *
 *	Enable the IDE PCI device. We attempt to enable the device in full
184 185 186
 *	but if that fails then we only need IO space. The PCI code should
 *	have setup the proper resources for us already for controllers in
 *	legacy mode.
187
 *
L
Linus Torvalds 已提交
188 189
 *	Returns zero on success or an error code
 */
190

191
static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
L
Linus Torvalds 已提交
192
{
193
	int ret, bars;
L
Linus Torvalds 已提交
194 195

	if (pci_enable_device(dev)) {
196
		ret = pci_enable_device_io(dev);
L
Linus Torvalds 已提交
197
		if (ret < 0) {
198 199
			printk(KERN_WARNING "%s %s: couldn't enable device\n",
				d->name, pci_name(dev));
L
Linus Torvalds 已提交
200 201
			goto out;
		}
202 203
		printk(KERN_WARNING "%s %s: BIOS configuration fixed\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
204 205 206
	}

	/*
207 208 209
	 * assume all devices can do 32-bit DMA for now, we can add
	 * a DMA mask field to the struct ide_port_info if we need it
	 * (or let lower level driver set the DMA mask)
L
Linus Torvalds 已提交
210 211 212
	 */
	ret = pci_set_dma_mask(dev, DMA_32BIT_MASK);
	if (ret < 0) {
213 214
		printk(KERN_ERR "%s %s: can't set DMA mask\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
215 216 217
		goto out;
	}

218 219 220 221
	if (d->host_flags & IDE_HFLAG_SINGLE)
		bars = (1 << 2) - 1;
	else
		bars = (1 << 4) - 1;
L
Linus Torvalds 已提交
222

223 224 225 226 227 228 229 230 231
	if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
		if (d->host_flags & IDE_HFLAG_CS5520)
			bars |= (1 << 2);
		else
			bars |= (1 << 4);
	}

	ret = pci_request_selected_regions(dev, bars, d->name);
	if (ret < 0)
232 233
		printk(KERN_ERR "%s %s: can't reserve resources\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
234 235 236 237 238 239 240
out:
	return ret;
}

/**
 *	ide_pci_configure	-	configure an unconfigured device
 *	@dev: PCI device
241
 *	@d: IDE port info
L
Linus Torvalds 已提交
242 243 244 245
 *
 *	Enable and configure the PCI device we have been passed.
 *	Returns zero on success or an error code.
 */
246

247
static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
L
Linus Torvalds 已提交
248 249 250 251 252 253 254 255 256
{
	u16 pcicmd = 0;
	/*
	 * PnP BIOS was *supposed* to have setup this device, but we
	 * can do it ourselves, so long as the BIOS has assigned an IRQ
	 * (or possibly the device is using a "legacy header" for IRQs).
	 * Maybe the user deliberately *disabled* the device,
	 * but we'll eventually ignore it again if no drives respond.
	 */
257 258
	if (ide_setup_pci_baseregs(dev, d->name) ||
	    pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
259 260
		printk(KERN_INFO "%s %s: device disabled (BIOS)\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
261 262 263
		return -ENODEV;
	}
	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
264 265
		printk(KERN_ERR "%s %s: error accessing PCI regs\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
266 267 268
		return -EIO;
	}
	if (!(pcicmd & PCI_COMMAND_IO)) {
269 270
		printk(KERN_ERR "%s %s: unable to enable IDE controller\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
271 272 273 274 275 276 277
		return -ENXIO;
	}
	return 0;
}

/**
 *	ide_pci_check_iomem	-	check a register is I/O
278 279 280
 *	@dev: PCI device
 *	@d: IDE port info
 *	@bar: BAR number
L
Linus Torvalds 已提交
281
 *
282 283
 *	Checks if a BAR is configured and points to MMIO space. If so,
 *	return an error code. Otherwise return 0
L
Linus Torvalds 已提交
284
 */
285

286 287
static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d,
			       int bar)
L
Linus Torvalds 已提交
288 289
{
	ulong flags = pci_resource_flags(dev, bar);
290

L
Linus Torvalds 已提交
291 292 293 294
	/* Unconfigured ? */
	if (!flags || pci_resource_len(dev, bar) == 0)
		return 0;

295 296
	/* I/O space */
	if (flags & IORESOURCE_IO)
L
Linus Torvalds 已提交
297
		return 0;
298

L
Linus Torvalds 已提交
299 300 301 302 303
	/* Bad */
	return -EINVAL;
}

/**
304
 *	ide_hw_configure	-	configure a hw_regs_t instance
L
Linus Torvalds 已提交
305
 *	@dev: PCI device holding interface
306
 *	@d: IDE port info
307
 *	@port: port number
308
 *	@hw: hw_regs_t instance corresponding to this port
L
Linus Torvalds 已提交
309 310 311 312 313
 *
 *	Perform the initial set up for the hardware interface structure. This
 *	is done per interface port rather than per PCI device. There may be
 *	more than one port per device.
 *
314
 *	Returns zero on success or an error code.
L
Linus Torvalds 已提交
315
 */
316

317
static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
318
			    unsigned int port, hw_regs_t *hw)
L
Linus Torvalds 已提交
319 320 321
{
	unsigned long ctl = 0, base = 0;

322
	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
323 324
		if (ide_pci_check_iomem(dev, d, 2 * port) ||
		    ide_pci_check_iomem(dev, d, 2 * port + 1)) {
325 326 327
			printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are "
				"reported as MEM for port %d!\n",
				d->name, pci_name(dev), port);
328
			return -EINVAL;
329
		}
330

L
Linus Torvalds 已提交
331 332
		ctl  = pci_resource_start(dev, 2*port+1);
		base = pci_resource_start(dev, 2*port);
333
	} else {
L
Linus Torvalds 已提交
334 335 336 337
		/* Use default values */
		ctl = port ? 0x374 : 0x3f4;
		base = port ? 0x170 : 0x1f0;
	}
338

339
	if (!base || !ctl) {
340 341
		printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n",
			d->name, pci_name(dev), port);
342
		return -EINVAL;
343 344
	}

345 346 347 348 349
	memset(hw, 0, sizeof(*hw));
	hw->dev = &dev->dev;
	hw->chipset = d->chipset ? d->chipset : ide_pci;
	ide_std_init_ports(hw, base, ctl | 2);

350
	return 0;
L
Linus Torvalds 已提交
351 352
}

353
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
L
Linus Torvalds 已提交
354 355
/**
 *	ide_hwif_setup_dma	-	configure DMA interface
356
 *	@hwif: IDE interface
357
 *	@d: IDE port info
L
Linus Torvalds 已提交
358 359 360 361 362
 *
 *	Set up the DMA base for the interface. Enable the master bits as
 *	necessary and attempt to bring the device DMA into a ready to use
 *	state
 */
363

364
int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
L
Linus Torvalds 已提交
365
{
366
	struct pci_dev *dev = to_pci_dev(hwif->dev);
L
Linus Torvalds 已提交
367

368
	if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
L
Linus Torvalds 已提交
369 370
	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
	     (dev->class & 0x80))) {
371
		unsigned long base = ide_pci_dma_base(hwif, d);
372

373 374 375 376 377
		if (base == 0)
			return -1;

		hwif->dma_base = base;

378 379 380
		if (hwif->dma_ops == NULL)
			hwif->dma_ops = &sff_dma_ops;

381 382 383 384
		if (ide_pci_check_simplex(hwif, d) < 0)
			return -1;

		if (ide_pci_set_master(dev, d->name) < 0)
385
			return -1;
386

387
		if (hwif->host_flags & IDE_HFLAG_MMIO)
388 389 390 391 392 393 394
			printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
		else
			printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx\n",
					 hwif->name, base, base + 7);

		hwif->extra_base = base + (hwif->channel ? 8 : 16);

395 396 397
		if (ide_allocate_dma_engine(hwif))
			return -1;
	}
398

399
	return 0;
400
}
401
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
L
Linus Torvalds 已提交
402 403 404 405

/**
 *	ide_setup_pci_controller	-	set up IDE PCI
 *	@dev: PCI device
406
 *	@d: IDE port info
L
Linus Torvalds 已提交
407 408 409 410 411 412
 *	@noisy: verbose flag
 *
 *	Set up the PCI and controller side of the IDE interface. This brings
 *	up the PCI side of the device, checks that the device is enabled
 *	and enables it if need be
 */
413

414 415
static int ide_setup_pci_controller(struct pci_dev *dev,
				    const struct ide_port_info *d, int noisy)
L
Linus Torvalds 已提交
416 417 418 419 420 421 422 423 424 425 426 427 428
{
	int ret;
	u16 pcicmd;

	if (noisy)
		ide_setup_pci_noise(dev, d);

	ret = ide_pci_enable(dev, d);
	if (ret < 0)
		goto out;

	ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
	if (ret < 0) {
429 430
		printk(KERN_ERR "%s %s: error accessing PCI regs\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
431 432 433 434 435 436
		goto out;
	}
	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
		ret = ide_pci_configure(dev, d);
		if (ret < 0)
			goto out;
437 438
		printk(KERN_INFO "%s %s: device enabled (Linux)\n",
			d->name, pci_name(dev));
L
Linus Torvalds 已提交
439 440 441 442 443 444 445 446 447
	}

out:
	return ret;
}

/**
 *	ide_pci_setup_ports	-	configure ports/devices on PCI IDE
 *	@dev: PCI device
448
 *	@d: IDE port info
449 450
 *	@hw: hw_regs_t instances corresponding to this PCI IDE device
 *	@hws: hw_regs_t pointers table to update
L
Linus Torvalds 已提交
451 452 453 454 455 456 457 458 459
 *
 *	Scan the interfaces attached to this device and do any
 *	necessary per port setup. Attach the devices and ask the
 *	generic DMA layer to do its work for us.
 *
 *	Normally called automaticall from do_ide_pci_setup_device,
 *	but is also used directly as a helper function by some controllers
 *	where the chipset setup is not the default PCI IDE one.
 */
460

461
void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
462
			 hw_regs_t *hw, hw_regs_t **hws)
L
Linus Torvalds 已提交
463
{
464
	int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
L
Linus Torvalds 已提交
465 466 467 468 469
	u8 tmp;

	/*
	 * Set up the IDE ports
	 */
470

471
	for (port = 0; port < channels; ++port) {
472
		const struct ide_pci_enablebit *e = &d->enablebits[port];
473

L
Linus Torvalds 已提交
474
		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
475
		    (tmp & e->mask) != e->val)) {
476 477
			printk(KERN_INFO "%s %s: IDE port disabled\n",
				d->name, pci_name(dev));
L
Linus Torvalds 已提交
478
			continue;	/* port not enabled */
479
		}
L
Linus Torvalds 已提交
480

481
		if (ide_hw_configure(dev, d, port, hw + port))
L
Linus Torvalds 已提交
482 483
			continue;

484
		*(hws + port) = hw + port;
485
	}
L
Linus Torvalds 已提交
486 487 488 489 490 491 492 493 494 495
}
EXPORT_SYMBOL_GPL(ide_pci_setup_ports);

/*
 * ide_setup_pci_device() looks at the primary/secondary interfaces
 * on a PCI IDE device and, if they are enabled, prepares the IDE driver
 * for use with them.  This generic code works for most PCI chipsets.
 *
 * One thing that is not standardized is the location of the
 * primary/secondary interface "enable/disable" bits.  For chipsets that
496
 * we "know" about, this information is in the struct ide_port_info;
L
Linus Torvalds 已提交
497 498
 * for all other chipsets, we just assume both interfaces are enabled.
 */
499
static int do_ide_setup_pci_device(struct pci_dev *dev,
500
				   const struct ide_port_info *d,
501
				   u8 noisy)
L
Linus Torvalds 已提交
502 503 504 505 506 507 508 509
{
	int pciirq, ret;

	/*
	 * Can we trust the reported IRQ?
	 */
	pciirq = dev->irq;

510 511 512 513 514 515
	/*
	 * This allows offboard ide-pci cards the enable a BIOS,
	 * verify interrupt settings of split-mirror pci-config
	 * space, place chipset into init-mode, and/or preserve
	 * an interrupt if the card is not native ide support.
	 */
516
	ret = d->init_chipset ? d->init_chipset(dev) : 0;
517 518 519
	if (ret < 0)
		goto out;

520
	if (ide_pci_is_in_compatibility_mode(dev)) {
L
Linus Torvalds 已提交
521
		if (noisy)
522 523
			printk(KERN_INFO "%s %s: not 100%% native mode: will "
				"probe irqs later\n", d->name, pci_name(dev));
524
		pciirq = 0;
525 526 527 528 529 530
	} else if (!pciirq && noisy) {
		printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n",
			d->name, pci_name(dev), pciirq);
	} else if (noisy) {
		printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n",
			d->name, pci_name(dev), pciirq);
L
Linus Torvalds 已提交
531 532
	}

533
	ret = pciirq;
L
Linus Torvalds 已提交
534 535 536 537
out:
	return ret;
}

538 539
int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
		     void *priv)
L
Linus Torvalds 已提交
540
{
541
	struct ide_host *host;
542
	hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
L
Linus Torvalds 已提交
543 544
	int ret;

545 546 547 548
	ret = ide_setup_pci_controller(dev, d, 1);
	if (ret < 0)
		goto out;

549
	ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
550

551 552 553 554 555 556 557 558 559 560
	host = ide_host_alloc(d, hws);
	if (host == NULL) {
		ret = -ENOMEM;
		goto out;
	}

	host->dev[0] = &dev->dev;

	host->host_priv = priv;

561
	pci_set_drvdata(dev, host);
562

563
	ret = do_ide_setup_pci_device(dev, d, 1);
564 565
	if (ret < 0)
		goto out;
566

567
	/* fixup IRQ */
568
	if (ide_pci_is_in_compatibility_mode(dev)) {
569 570
		hw[0].irq = pci_get_legacy_ide_irq(dev, 0);
		hw[1].irq = pci_get_legacy_ide_irq(dev, 1);
571 572
	} else
		hw[1].irq = hw[0].irq = ret;
573

574 575 576
	ret = ide_host_register(host, d, hws);
	if (ret)
		ide_host_free(host);
577
out:
L
Linus Torvalds 已提交
578 579
	return ret;
}
580
EXPORT_SYMBOL_GPL(ide_pci_init_one);
L
Linus Torvalds 已提交
581

582 583
int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
		     const struct ide_port_info *d, void *priv)
L
Linus Torvalds 已提交
584 585
{
	struct pci_dev *pdev[] = { dev1, dev2 };
586
	struct ide_host *host;
L
Linus Torvalds 已提交
587
	int ret, i;
588
	hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
L
Linus Torvalds 已提交
589 590

	for (i = 0; i < 2; i++) {
591 592 593 594
		ret = ide_setup_pci_controller(pdev[i], d, !i);
		if (ret < 0)
			goto out;

595
		ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
596
	}
597

598 599 600 601 602 603 604 605 606 607 608
	host = ide_host_alloc(d, hws);
	if (host == NULL) {
		ret = -ENOMEM;
		goto out;
	}

	host->dev[0] = &dev1->dev;
	host->dev[1] = &dev2->dev;

	host->host_priv = priv;

609 610
	pci_set_drvdata(pdev[0], host);
	pci_set_drvdata(pdev[1], host);
611 612

	for (i = 0; i < 2; i++) {
613 614
		ret = do_ide_setup_pci_device(pdev[i], d, !i);

L
Linus Torvalds 已提交
615 616 617 618 619 620
		/*
		 * FIXME: Mom, mom, they stole me the helper function to undo
		 * do_ide_setup_pci_device() on the first device!
		 */
		if (ret < 0)
			goto out;
621

622
		/* fixup IRQ */
623
		if (ide_pci_is_in_compatibility_mode(pdev[i])) {
624 625
			hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0);
			hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1);
626 627
		} else
			hw[i*2 + 1].irq = hw[i*2].irq = ret;
L
Linus Torvalds 已提交
628 629
	}

630 631 632
	ret = ide_host_register(host, d, hws);
	if (ret)
		ide_host_free(host);
L
Linus Torvalds 已提交
633 634 635
out:
	return ret;
}
636
EXPORT_SYMBOL_GPL(ide_pci_init_two);
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666

void ide_pci_remove(struct pci_dev *dev)
{
	struct ide_host *host = pci_get_drvdata(dev);
	struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
	int bars;

	if (host->host_flags & IDE_HFLAG_SINGLE)
		bars = (1 << 2) - 1;
	else
		bars = (1 << 4) - 1;

	if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) {
		if (host->host_flags & IDE_HFLAG_CS5520)
			bars |= (1 << 2);
		else
			bars |= (1 << 4);
	}

	ide_host_remove(host);

	if (dev2)
		pci_release_selected_regions(dev2, bars);
	pci_release_selected_regions(dev, bars);

	if (dev2)
		pci_disable_device(dev2);
	pci_disable_device(dev);
}
EXPORT_SYMBOL_GPL(ide_pci_remove);
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

#ifdef CONFIG_PM
int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
{
	pci_save_state(dev);
	pci_disable_device(dev);
	pci_set_power_state(dev, pci_choose_state(dev, state));

	return 0;
}
EXPORT_SYMBOL_GPL(ide_pci_suspend);

int ide_pci_resume(struct pci_dev *dev)
{
	struct ide_host *host = pci_get_drvdata(dev);
	int rc;

	pci_set_power_state(dev, PCI_D0);

	rc = pci_enable_device(dev);
	if (rc)
		return rc;

	pci_restore_state(dev);
	pci_set_master(dev);

	if (host->init_chipset)
		host->init_chipset(dev);

	return 0;
}
EXPORT_SYMBOL_GPL(ide_pci_resume);
#endif