diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-05-12 15:03:42 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-12 15:03:42 -0400 |
commit | 907f4678c114a125fe4584758681c31bf3d627da (patch) | |
tree | 630fac16df73c923db4ae4dd1ab8a24b1a8a4688 /drivers/scsi/ahci.c | |
parent | 88d7bd8cb9eb8d64bf7997600b0d64f7834047c5 (diff) |
[libata ahci] support PCI MSI interrupt vector
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index da5bd33d982d..5e2a1e8b9039 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -152,6 +152,7 @@ struct ahci_sg { | |||
152 | 152 | ||
153 | struct ahci_host_priv { | 153 | struct ahci_host_priv { |
154 | unsigned long flags; | 154 | unsigned long flags; |
155 | unsigned int have_msi; /* is PCI MSI enabled? */ | ||
155 | u32 cap; /* cache of HOST_CAP register */ | 156 | u32 cap; /* cache of HOST_CAP register */ |
156 | u32 port_map; /* cache of HOST_PORTS_IMPL reg */ | 157 | u32 port_map; /* cache of HOST_PORTS_IMPL reg */ |
157 | }; | 158 | }; |
@@ -182,6 +183,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); | |||
182 | static u8 ahci_check_status(struct ata_port *ap); | 183 | static u8 ahci_check_status(struct ata_port *ap); |
183 | static u8 ahci_check_err(struct ata_port *ap); | 184 | static u8 ahci_check_err(struct ata_port *ap); |
184 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); | 185 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); |
186 | static void ahci_remove_one (struct pci_dev *pdev); | ||
185 | 187 | ||
186 | static Scsi_Host_Template ahci_sht = { | 188 | static Scsi_Host_Template ahci_sht = { |
187 | .module = THIS_MODULE, | 189 | .module = THIS_MODULE, |
@@ -271,7 +273,7 @@ static struct pci_driver ahci_pci_driver = { | |||
271 | .name = DRV_NAME, | 273 | .name = DRV_NAME, |
272 | .id_table = ahci_pci_tbl, | 274 | .id_table = ahci_pci_tbl, |
273 | .probe = ahci_init_one, | 275 | .probe = ahci_init_one, |
274 | .remove = ata_pci_remove_one, | 276 | .remove = ahci_remove_one, |
275 | }; | 277 | }; |
276 | 278 | ||
277 | 279 | ||
@@ -876,15 +878,19 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
876 | } | 878 | } |
877 | 879 | ||
878 | /* move to PCI layer, integrate w/ MSI stuff */ | 880 | /* move to PCI layer, integrate w/ MSI stuff */ |
879 | static void pci_enable_intx(struct pci_dev *pdev) | 881 | static void pci_intx(struct pci_dev *pdev, int enable) |
880 | { | 882 | { |
881 | u16 pci_command; | 883 | u16 pci_command, new; |
882 | 884 | ||
883 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); | 885 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); |
884 | if (pci_command & PCI_COMMAND_INTX_DISABLE) { | 886 | |
885 | pci_command &= ~PCI_COMMAND_INTX_DISABLE; | 887 | if (enable) |
888 | new = pci_command & ~PCI_COMMAND_INTX_DISABLE; | ||
889 | else | ||
890 | new = pci_command | PCI_COMMAND_INTX_DISABLE; | ||
891 | |||
892 | if (new != pci_command) | ||
886 | pci_write_config_word(pdev, PCI_COMMAND, pci_command); | 893 | pci_write_config_word(pdev, PCI_COMMAND, pci_command); |
887 | } | ||
888 | } | 894 | } |
889 | 895 | ||
890 | static void ahci_print_info(struct ata_probe_ent *probe_ent) | 896 | static void ahci_print_info(struct ata_probe_ent *probe_ent) |
@@ -966,7 +972,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
966 | unsigned long base; | 972 | unsigned long base; |
967 | void *mmio_base; | 973 | void *mmio_base; |
968 | unsigned int board_idx = (unsigned int) ent->driver_data; | 974 | unsigned int board_idx = (unsigned int) ent->driver_data; |
969 | int pci_dev_busy = 0; | 975 | int have_msi, pci_dev_busy = 0; |
970 | int rc; | 976 | int rc; |
971 | 977 | ||
972 | VPRINTK("ENTER\n"); | 978 | VPRINTK("ENTER\n"); |
@@ -984,12 +990,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
984 | goto err_out; | 990 | goto err_out; |
985 | } | 991 | } |
986 | 992 | ||
987 | pci_enable_intx(pdev); | 993 | if (pci_enable_msi(pdev) == 0) |
994 | have_msi = 1; | ||
995 | else { | ||
996 | pci_intx(pdev, 1); | ||
997 | have_msi = 0; | ||
998 | } | ||
988 | 999 | ||
989 | probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); | 1000 | probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); |
990 | if (probe_ent == NULL) { | 1001 | if (probe_ent == NULL) { |
991 | rc = -ENOMEM; | 1002 | rc = -ENOMEM; |
992 | goto err_out_regions; | 1003 | goto err_out_msi; |
993 | } | 1004 | } |
994 | 1005 | ||
995 | memset(probe_ent, 0, sizeof(*probe_ent)); | 1006 | memset(probe_ent, 0, sizeof(*probe_ent)); |
@@ -1022,6 +1033,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1022 | probe_ent->mmio_base = mmio_base; | 1033 | probe_ent->mmio_base = mmio_base; |
1023 | probe_ent->private_data = hpriv; | 1034 | probe_ent->private_data = hpriv; |
1024 | 1035 | ||
1036 | hpriv->have_msi = have_msi; | ||
1037 | |||
1025 | /* initialize adapter */ | 1038 | /* initialize adapter */ |
1026 | rc = ahci_host_init(probe_ent); | 1039 | rc = ahci_host_init(probe_ent); |
1027 | if (rc) | 1040 | if (rc) |
@@ -1041,7 +1054,11 @@ err_out_iounmap: | |||
1041 | iounmap(mmio_base); | 1054 | iounmap(mmio_base); |
1042 | err_out_free_ent: | 1055 | err_out_free_ent: |
1043 | kfree(probe_ent); | 1056 | kfree(probe_ent); |
1044 | err_out_regions: | 1057 | err_out_msi: |
1058 | if (have_msi) | ||
1059 | pci_disable_msi(pdev); | ||
1060 | else | ||
1061 | pci_intx(pdev, 0); | ||
1045 | pci_release_regions(pdev); | 1062 | pci_release_regions(pdev); |
1046 | err_out: | 1063 | err_out: |
1047 | if (!pci_dev_busy) | 1064 | if (!pci_dev_busy) |
@@ -1049,6 +1066,42 @@ err_out: | |||
1049 | return rc; | 1066 | return rc; |
1050 | } | 1067 | } |
1051 | 1068 | ||
1069 | static void ahci_remove_one (struct pci_dev *pdev) | ||
1070 | { | ||
1071 | struct device *dev = pci_dev_to_dev(pdev); | ||
1072 | struct ata_host_set *host_set = dev_get_drvdata(dev); | ||
1073 | struct ahci_host_priv *hpriv = host_set->private_data; | ||
1074 | struct ata_port *ap; | ||
1075 | unsigned int i; | ||
1076 | int have_msi; | ||
1077 | |||
1078 | for (i = 0; i < host_set->n_ports; i++) { | ||
1079 | ap = host_set->ports[i]; | ||
1080 | |||
1081 | scsi_remove_host(ap->host); | ||
1082 | } | ||
1083 | |||
1084 | have_msi = hpriv->have_msi; | ||
1085 | free_irq(host_set->irq, host_set); | ||
1086 | host_set->ops->host_stop(host_set); | ||
1087 | iounmap(host_set->mmio_base); | ||
1088 | |||
1089 | for (i = 0; i < host_set->n_ports; i++) { | ||
1090 | ap = host_set->ports[i]; | ||
1091 | |||
1092 | ata_scsi_release(ap->host); | ||
1093 | scsi_host_put(ap->host); | ||
1094 | } | ||
1095 | |||
1096 | if (have_msi) | ||
1097 | pci_disable_msi(pdev); | ||
1098 | else | ||
1099 | pci_intx(pdev, 0); | ||
1100 | pci_release_regions(pdev); | ||
1101 | kfree(host_set); | ||
1102 | pci_disable_device(pdev); | ||
1103 | dev_set_drvdata(dev, NULL); | ||
1104 | } | ||
1052 | 1105 | ||
1053 | static int __init ahci_init(void) | 1106 | static int __init ahci_init(void) |
1054 | { | 1107 | { |