Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e6b79fa authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: factor out ata_pci_activate_sff_host() from ata_pci_one()



Factor out ata_pci_activate_sff_host() from ata_pci_one().  This does
about the same thing as ata_host_activate() but needs to be separate
because SFF controllers use different and multiple IRQs in legacy
mode.

This will be used to make SFF LLD initialization more flexible.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent cadb7345
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7629,6 +7629,7 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_pci_init_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
#ifdef CONFIG_PM
+103 −84
Original line number Diff line number Diff line
@@ -713,6 +713,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev,
	return rc;
}

/**
 *	ata_pci_activate_sff_host - start SFF host, request IRQ and register it
 *	@host: target SFF ATA host
 *	@irq_handler: irq_handler used when requesting IRQ(s)
 *	@sht: scsi_host_template to use when registering the host
 *
 *	This is the counterpart of ata_host_activate() for SFF ATA
 *	hosts.  This separate helper is necessary because SFF hosts
 *	use two separate interrupts in legacy mode.
 *
 *	LOCKING:
 *	Inherited from calling layer (may sleep).
 *
 *	RETURNS:
 *	0 on success, -errno otherwise.
 */
int ata_pci_activate_sff_host(struct ata_host *host,
			      irq_handler_t irq_handler,
			      struct scsi_host_template *sht)
{
	struct device *dev = host->dev;
	struct pci_dev *pdev = to_pci_dev(dev);
	const char *drv_name = dev_driver_string(host->dev);
	int legacy_mode = 0, rc;

	rc = ata_host_start(host);
	if (rc)
		return rc;

	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
		u8 tmp8, mask;

		/* TODO: What if one channel is in native mode ... */
		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
		mask = (1 << 2) | (1 << 0);
		if ((tmp8 & mask) != mask)
			legacy_mode = 1;
#if defined(CONFIG_NO_ATA_LEGACY)
		/* Some platforms with PCI limits cannot address compat
		   port space. In that case we punt if their firmware has
		   left a device in compatibility mode */
		if (legacy_mode) {
			printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
			return -EOPNOTSUPP;
		}
#endif
	}

	if (!devres_open_group(dev, NULL, GFP_KERNEL))
		return -ENOMEM;

	if (!legacy_mode && pdev->irq) {
		rc = devm_request_irq(dev, pdev->irq, irq_handler,
				      IRQF_SHARED, drv_name, host);
		if (rc)
			goto out;

		ata_port_desc(host->ports[0], "irq %d", pdev->irq);
		ata_port_desc(host->ports[1], "irq %d", pdev->irq);
	} else if (legacy_mode) {
		if (!ata_port_is_dummy(host->ports[0])) {
			rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
					      irq_handler, IRQF_SHARED,
					      drv_name, host);
			if (rc)
				goto out;

			ata_port_desc(host->ports[0], "irq %d",
				      ATA_PRIMARY_IRQ(pdev));
		}

		if (!ata_port_is_dummy(host->ports[1])) {
			rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
					      irq_handler, IRQF_SHARED,
					      drv_name, host);
			if (rc)
				goto out;

			ata_port_desc(host->ports[1], "irq %d",
				      ATA_SECONDARY_IRQ(pdev));
		}
	}

	rc = ata_host_register(host, sht);
 out:
	if (rc == 0)
		devres_remove_group(dev, NULL);
	else
		devres_release_group(dev, NULL);

	return rc;
}

/**
 *	ata_pci_init_one - Initialize/register PCI IDE host controller
 *	@pdev: Controller to be initialized
@@ -742,9 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev,
	struct device *dev = &pdev->dev;
	const struct ata_port_info *pi = NULL;
	struct ata_host *host = NULL;
	const char *drv_name = dev_driver_string(&pdev->dev);
	u8 mask;
	int legacy_mode = 0;
	int i, rc;

	DPRINTK("ENTER\n");
@@ -766,95 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev,
	if (!devres_open_group(dev, NULL, GFP_KERNEL))
		return -ENOMEM;

	/* FIXME: Really for ATA it isn't safe because the device may be
	   multi-purpose and we want to leave it alone if it was already
	   enabled. Secondly for shared use as Arjan says we want refcounting

	   Checking dev->is_enabled is insufficient as this is not set at
	   boot for the primary video which is BIOS enabled
	  */

	rc = pcim_enable_device(pdev);
	if (rc)
		goto err_out;
		goto out;

	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
		u8 tmp8;

		/* TODO: What if one channel is in native mode ... */
		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
		mask = (1 << 2) | (1 << 0);
		if ((tmp8 & mask) != mask)
			legacy_mode = 1;
#if defined(CONFIG_NO_ATA_LEGACY)
		/* Some platforms with PCI limits cannot address compat
		   port space. In that case we punt if their firmware has
		   left a device in compatibility mode */
		if (legacy_mode) {
			printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
			rc = -EOPNOTSUPP;
			goto err_out;
		}
#endif
	}

	/* prepare host */
	/* prepare and activate SFF host */
	rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
	if (rc)
		goto err_out;
		goto out;

	pci_set_master(pdev);
	rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler,
				       pi->sht);
 out:
	if (rc == 0)
		devres_remove_group(&pdev->dev, NULL);
	else
		devres_release_group(&pdev->dev, NULL);

	/* start host and request IRQ */
	rc = ata_host_start(host);
	if (rc)
		goto err_out;

	if (!legacy_mode && pdev->irq) {
		/* We may have no IRQ assigned in which case we can poll. This
		   shouldn't happen on a sane system but robustness is cheap
		   in this case */
		rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
				      IRQF_SHARED, drv_name, host);
		if (rc)
			goto err_out;

		ata_port_desc(host->ports[0], "irq %d", pdev->irq);
		ata_port_desc(host->ports[1], "irq %d", pdev->irq);
	} else if (legacy_mode) {
		if (!ata_port_is_dummy(host->ports[0])) {
			rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
					      pi->port_ops->irq_handler,
					      IRQF_SHARED, drv_name, host);
			if (rc)
				goto err_out;

			ata_port_desc(host->ports[0], "irq %d",
				      ATA_PRIMARY_IRQ(pdev));
		}

		if (!ata_port_is_dummy(host->ports[1])) {
			rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
					      pi->port_ops->irq_handler,
					      IRQF_SHARED, drv_name, host);
			if (rc)
				goto err_out;

			ata_port_desc(host->ports[1], "irq %d",
				      ATA_SECONDARY_IRQ(pdev));
		}
	}

	/* register */
	rc = ata_host_register(host, pi->sht);
	if (rc)
		goto err_out;

	devres_remove_group(dev, NULL);
	return 0;

err_out:
	devres_release_group(dev, NULL);
	return rc;
}

+3 −0
Original line number Diff line number Diff line
@@ -1033,6 +1033,9 @@ extern int ata_pci_init_bmdma(struct ata_host *host);
extern int ata_pci_prepare_sff_host(struct pci_dev *pdev,
				    const struct ata_port_info * const * ppi,
				    struct ata_host **r_host);
extern int ata_pci_activate_sff_host(struct ata_host *host,
				     irq_handler_t irq_handler,
				     struct scsi_host_template *sht);
extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
extern unsigned long ata_pci_default_filter(struct ata_device *dev,
					    unsigned long xfer_mask);