|
@@ -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;
|
|
|
}
|
|
|
|