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: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Tejun Heo 2008-01-18 18:36:28 +09:00 committed by Jeff Garzik
parent cadb7345d9
commit 4e6b79fa61
3 changed files with 107 additions and 84 deletions

View File

@ -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_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); 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_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one);
#ifdef CONFIG_PM #ifdef CONFIG_PM

View File

@ -713,6 +713,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev,
return rc; 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 * ata_pci_init_one - Initialize/register PCI IDE host controller
* @pdev: Controller to be initialized * @pdev: Controller to be initialized
@ -742,9 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev,
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct ata_port_info *pi = NULL; const struct ata_port_info *pi = NULL;
struct ata_host *host = NULL; struct ata_host *host = NULL;
const char *drv_name = dev_driver_string(&pdev->dev);
u8 mask;
int legacy_mode = 0;
int i, rc; int i, rc;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
@ -766,95 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev,
if (!devres_open_group(dev, NULL, GFP_KERNEL)) if (!devres_open_group(dev, NULL, GFP_KERNEL))
return -ENOMEM; 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); rc = pcim_enable_device(pdev);
if (rc) if (rc)
goto err_out; goto out;
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { /* prepare and activate SFF host */
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 */
rc = ata_pci_prepare_sff_host(pdev, ppi, &host); rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
if (rc) if (rc)
goto err_out; goto out;
pci_set_master(pdev); 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; return rc;
} }

View File

@ -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, extern int ata_pci_prepare_sff_host(struct pci_dev *pdev,
const struct ata_port_info * const * ppi, const struct ata_port_info * const * ppi,
struct ata_host **r_host); 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 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, extern unsigned long ata_pci_default_filter(struct ata_device *dev,
unsigned long xfer_mask); unsigned long xfer_mask);