diff options
| -rw-r--r-- | drivers/ata/libata-core.c | 1 | ||||
| -rw-r--r-- | drivers/ata/libata-sff.c | 187 | ||||
| -rw-r--r-- | include/linux/libata.h | 3 |
3 files changed, 107 insertions, 84 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8c82193b077e..ce803d18e96a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
| @@ -7629,6 +7629,7 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits); | |||
| 7629 | EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); | 7629 | EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); |
| 7630 | EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); | 7630 | EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); |
| 7631 | EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); | 7631 | EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); |
| 7632 | EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); | ||
| 7632 | EXPORT_SYMBOL_GPL(ata_pci_init_one); | 7633 | EXPORT_SYMBOL_GPL(ata_pci_init_one); |
| 7633 | EXPORT_SYMBOL_GPL(ata_pci_remove_one); | 7634 | EXPORT_SYMBOL_GPL(ata_pci_remove_one); |
| 7634 | #ifdef CONFIG_PM | 7635 | #ifdef CONFIG_PM |
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 | ||
diff --git a/include/linux/libata.h b/include/linux/libata.h index ccb055636f37..4374c4277780 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -1033,6 +1033,9 @@ extern int ata_pci_init_bmdma(struct ata_host *host); | |||
| 1033 | extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, | 1033 | extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, |
| 1034 | const struct ata_port_info * const * ppi, | 1034 | const struct ata_port_info * const * ppi, |
| 1035 | struct ata_host **r_host); | 1035 | struct ata_host **r_host); |
| 1036 | extern int ata_pci_activate_sff_host(struct ata_host *host, | ||
| 1037 | irq_handler_t irq_handler, | ||
| 1038 | struct scsi_host_template *sht); | ||
| 1036 | extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); | 1039 | extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); |
| 1037 | extern unsigned long ata_pci_default_filter(struct ata_device *dev, | 1040 | extern unsigned long ata_pci_default_filter(struct ata_device *dev, |
| 1038 | unsigned long xfer_mask); | 1041 | unsigned long xfer_mask); |
