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:
parent
cadb7345d9
commit
4e6b79fa61
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue