diff options
author | Tejun Heo <htejun@gmail.com> | 2008-01-18 04:36:28 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2008-01-23 05:24:16 -0500 |
commit | 4e6b79fa61091a0ed9b0af0f573cc257772cd88d (patch) | |
tree | cd3e9dca0355741713d038b0068cd4ba32f87b56 /drivers/ata/libata-sff.c | |
parent | cadb7345d92628d46cccd3765cc15cb9cd6abccf (diff) |
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>
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r-- | drivers/ata/libata-sff.c | 187 |
1 files changed, 103 insertions, 84 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 97dd8f2796b7..60cd4b179766 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c | |||
@@ -714,6 +714,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, | |||
714 | } | 714 | } |
715 | 715 | ||
716 | /** | 716 | /** |
717 | * ata_pci_activate_sff_host - start SFF host, request IRQ and register it | ||
718 | * @host: target SFF ATA host | ||
719 | * @irq_handler: irq_handler used when requesting IRQ(s) | ||
720 | * @sht: scsi_host_template to use when registering the host | ||
721 | * | ||
722 | * This is the counterpart of ata_host_activate() for SFF ATA | ||
723 | * hosts. This separate helper is necessary because SFF hosts | ||
724 | * use two separate interrupts in legacy mode. | ||
725 | * | ||
726 | * LOCKING: | ||
727 | * Inherited from calling layer (may sleep). | ||
728 | * | ||
729 | * RETURNS: | ||
730 | * 0 on success, -errno otherwise. | ||
731 | */ | ||
732 | int ata_pci_activate_sff_host(struct ata_host *host, | ||
733 | irq_handler_t irq_handler, | ||
734 | struct scsi_host_template *sht) | ||
735 | { | ||
736 | struct device *dev = host->dev; | ||
737 | struct pci_dev *pdev = to_pci_dev(dev); | ||
738 | const char *drv_name = dev_driver_string(host->dev); | ||
739 | int legacy_mode = 0, rc; | ||
740 | |||
741 | rc = ata_host_start(host); | ||
742 | if (rc) | ||
743 | return rc; | ||
744 | |||
745 | if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { | ||
746 | u8 tmp8, mask; | ||
747 | |||
748 | /* TODO: What if one channel is in native mode ... */ | ||
749 | pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); | ||
750 | mask = (1 << 2) | (1 << 0); | ||
751 | if ((tmp8 & mask) != mask) | ||
752 | legacy_mode = 1; | ||
753 | #if defined(CONFIG_NO_ATA_LEGACY) | ||
754 | /* Some platforms with PCI limits cannot address compat | ||
755 | port space. In that case we punt if their firmware has | ||
756 | left a device in compatibility mode */ | ||
757 | if (legacy_mode) { | ||
758 | printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); | ||
759 | return -EOPNOTSUPP; | ||
760 | } | ||
761 | #endif | ||
762 | } | ||
763 | |||
764 | if (!devres_open_group(dev, NULL, GFP_KERNEL)) | ||
765 | return -ENOMEM; | ||
766 | |||
767 | if (!legacy_mode && pdev->irq) { | ||
768 | rc = devm_request_irq(dev, pdev->irq, irq_handler, | ||
769 | IRQF_SHARED, drv_name, host); | ||
770 | if (rc) | ||
771 | goto out; | ||
772 | |||
773 | ata_port_desc(host->ports[0], "irq %d", pdev->irq); | ||
774 | ata_port_desc(host->ports[1], "irq %d", pdev->irq); | ||
775 | } else if (legacy_mode) { | ||
776 | if (!ata_port_is_dummy(host->ports[0])) { | ||
777 | rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), | ||
778 | irq_handler, IRQF_SHARED, | ||
779 | drv_name, host); | ||
780 | if (rc) | ||
781 | goto out; | ||
782 | |||
783 | ata_port_desc(host->ports[0], "irq %d", | ||
784 | ATA_PRIMARY_IRQ(pdev)); | ||
785 | } | ||
786 | |||
787 | if (!ata_port_is_dummy(host->ports[1])) { | ||
788 | rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), | ||
789 | irq_handler, IRQF_SHARED, | ||
790 | drv_name, host); | ||
791 | if (rc) | ||
792 | goto out; | ||
793 | |||
794 | ata_port_desc(host->ports[1], "irq %d", | ||
795 | ATA_SECONDARY_IRQ(pdev)); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | rc = ata_host_register(host, sht); | ||
800 | out: | ||
801 | if (rc == 0) | ||
802 | devres_remove_group(dev, NULL); | ||
803 | else | ||
804 | devres_release_group(dev, NULL); | ||
805 | |||
806 | return rc; | ||
807 | } | ||
808 | |||
809 | /** | ||
717 | * ata_pci_init_one - Initialize/register PCI IDE host controller | 810 | * ata_pci_init_one - Initialize/register PCI IDE host controller |
718 | * @pdev: Controller to be initialized | 811 | * @pdev: Controller to be initialized |
719 | * @ppi: array of port_info, must be enough for two ports | 812 | * @ppi: array of port_info, must be enough for two ports |
@@ -742,9 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev, | |||
742 | struct device *dev = &pdev->dev; | 835 | struct device *dev = &pdev->dev; |
743 | const struct ata_port_info *pi = NULL; | 836 | const struct ata_port_info *pi = NULL; |
744 | struct ata_host *host = NULL; | 837 | struct ata_host *host = NULL; |
745 | const char *drv_name = dev_driver_string(&pdev->dev); | ||
746 | u8 mask; | ||
747 | int legacy_mode = 0; | ||
748 | int i, rc; | 838 | int i, rc; |
749 | 839 | ||
750 | DPRINTK("ENTER\n"); | 840 | DPRINTK("ENTER\n"); |
@@ -766,95 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev, | |||
766 | if (!devres_open_group(dev, NULL, GFP_KERNEL)) | 856 | if (!devres_open_group(dev, NULL, GFP_KERNEL)) |
767 | return -ENOMEM; | 857 | return -ENOMEM; |
768 | 858 | ||
769 | /* FIXME: Really for ATA it isn't safe because the device may be | ||
770 | multi-purpose and we want to leave it alone if it was already | ||
771 | enabled. Secondly for shared use as Arjan says we want refcounting | ||
772 | |||
773 | Checking dev->is_enabled is insufficient as this is not set at | ||
774 | boot for the primary video which is BIOS enabled | ||
775 | */ | ||
776 | |||
777 | rc = pcim_enable_device(pdev); | 859 | rc = pcim_enable_device(pdev); |
778 | if (rc) | 860 | if (rc) |
779 | goto err_out; | 861 | goto out; |
780 | 862 | ||
781 | if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { | 863 | /* prepare and activate SFF host */ |
782 | u8 tmp8; | ||
783 | |||
784 | /* TODO: What if one channel is in native mode ... */ | ||
785 | pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); | ||
786 | mask = (1 << 2) | (1 << 0); | ||
787 | if ((tmp8 & mask) != mask) | ||
788 | legacy_mode = 1; | ||
789 | #if defined(CONFIG_NO_ATA_LEGACY) | ||
790 | /* Some platforms with PCI limits cannot address compat | ||
791 | port space. In that case we punt if their firmware has | ||
792 | left a device in compatibility mode */ | ||
793 | if (legacy_mode) { | ||
794 | printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); | ||
795 | rc = -EOPNOTSUPP; | ||
796 | goto err_out; | ||
797 | } | ||
798 | #endif | ||
799 | } | ||
800 | |||
801 | /* prepare host */ | ||
802 | rc = ata_pci_prepare_sff_host(pdev, ppi, &host); | 864 | rc = ata_pci_prepare_sff_host(pdev, ppi, &host); |
803 | if (rc) | 865 | if (rc) |
804 | goto err_out; | 866 | goto out; |
805 | 867 | ||
806 | pci_set_master(pdev); | 868 | pci_set_master(pdev); |
869 | rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler, | ||
870 | pi->sht); | ||
871 | out: | ||
872 | if (rc == 0) | ||
873 | devres_remove_group(&pdev->dev, NULL); | ||
874 | else | ||
875 | devres_release_group(&pdev->dev, NULL); | ||
807 | 876 | ||
808 | /* start host and request IRQ */ | ||
809 | rc = ata_host_start(host); | ||
810 | if (rc) | ||
811 | goto err_out; | ||
812 | |||
813 | if (!legacy_mode && pdev->irq) { | ||
814 | /* We may have no IRQ assigned in which case we can poll. This | ||
815 | shouldn't happen on a sane system but robustness is cheap | ||
816 | in this case */ | ||
817 | rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler, | ||
818 | IRQF_SHARED, drv_name, host); | ||
819 | if (rc) | ||
820 | goto err_out; | ||
821 | |||
822 | ata_port_desc(host->ports[0], "irq %d", pdev->irq); | ||
823 | ata_port_desc(host->ports[1], "irq %d", pdev->irq); | ||
824 | } else if (legacy_mode) { | ||
825 | if (!ata_port_is_dummy(host->ports[0])) { | ||
826 | rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), | ||
827 | pi->port_ops->irq_handler, | ||
828 | IRQF_SHARED, drv_name, host); | ||
829 | if (rc) | ||
830 | goto err_out; | ||
831 | |||
832 | ata_port_desc(host->ports[0], "irq %d", | ||
833 | ATA_PRIMARY_IRQ(pdev)); | ||
834 | } | ||
835 | |||
836 | if (!ata_port_is_dummy(host->ports[1])) { | ||
837 | rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), | ||
838 | pi->port_ops->irq_handler, | ||
839 | IRQF_SHARED, drv_name, host); | ||
840 | if (rc) | ||
841 | goto err_out; | ||
842 | |||
843 | ata_port_desc(host->ports[1], "irq %d", | ||
844 | ATA_SECONDARY_IRQ(pdev)); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | /* register */ | ||
849 | rc = ata_host_register(host, pi->sht); | ||
850 | if (rc) | ||
851 | goto err_out; | ||
852 | |||
853 | devres_remove_group(dev, NULL); | ||
854 | return 0; | ||
855 | |||
856 | err_out: | ||
857 | devres_release_group(dev, NULL); | ||
858 | return rc; | 877 | return rc; |
859 | } | 878 | } |
860 | 879 | ||