diff options
Diffstat (limited to 'drivers/ata/sata_sil24.c')
-rw-r--r-- | drivers/ata/sata_sil24.c | 122 |
1 files changed, 44 insertions, 78 deletions
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 5614df8c1ce2..e6223ba667da 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c | |||
@@ -323,7 +323,7 @@ struct sil24_port_priv { | |||
323 | struct ata_taskfile tf; /* Cached taskfile registers */ | 323 | struct ata_taskfile tf; /* Cached taskfile registers */ |
324 | }; | 324 | }; |
325 | 325 | ||
326 | static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev); | 326 | static void sil24_dev_config(struct ata_device *dev); |
327 | static u8 sil24_check_status(struct ata_port *ap); | 327 | static u8 sil24_check_status(struct ata_port *ap); |
328 | static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); | 328 | static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); |
329 | static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); | 329 | static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); |
@@ -331,7 +331,6 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); | |||
331 | static void sil24_qc_prep(struct ata_queued_cmd *qc); | 331 | static void sil24_qc_prep(struct ata_queued_cmd *qc); |
332 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); | 332 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); |
333 | static void sil24_irq_clear(struct ata_port *ap); | 333 | static void sil24_irq_clear(struct ata_port *ap); |
334 | static irqreturn_t sil24_interrupt(int irq, void *dev_instance); | ||
335 | static void sil24_freeze(struct ata_port *ap); | 334 | static void sil24_freeze(struct ata_port *ap); |
336 | static void sil24_thaw(struct ata_port *ap); | 335 | static void sil24_thaw(struct ata_port *ap); |
337 | static void sil24_error_handler(struct ata_port *ap); | 336 | static void sil24_error_handler(struct ata_port *ap); |
@@ -401,7 +400,6 @@ static const struct ata_port_operations sil24_ops = { | |||
401 | .qc_prep = sil24_qc_prep, | 400 | .qc_prep = sil24_qc_prep, |
402 | .qc_issue = sil24_qc_issue, | 401 | .qc_issue = sil24_qc_issue, |
403 | 402 | ||
404 | .irq_handler = sil24_interrupt, | ||
405 | .irq_clear = sil24_irq_clear, | 403 | .irq_clear = sil24_irq_clear, |
406 | .irq_on = ata_dummy_irq_on, | 404 | .irq_on = ata_dummy_irq_on, |
407 | .irq_ack = ata_dummy_irq_ack, | 405 | .irq_ack = ata_dummy_irq_ack, |
@@ -424,10 +422,9 @@ static const struct ata_port_operations sil24_ops = { | |||
424 | #define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) | 422 | #define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30) |
425 | #define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) | 423 | #define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1) |
426 | 424 | ||
427 | static struct ata_port_info sil24_port_info[] = { | 425 | static const struct ata_port_info sil24_port_info[] = { |
428 | /* sil_3124 */ | 426 | /* sil_3124 */ |
429 | { | 427 | { |
430 | .sht = &sil24_sht, | ||
431 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | | 428 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | |
432 | SIL24_FLAG_PCIX_IRQ_WOC, | 429 | SIL24_FLAG_PCIX_IRQ_WOC, |
433 | .pio_mask = 0x1f, /* pio0-4 */ | 430 | .pio_mask = 0x1f, /* pio0-4 */ |
@@ -437,7 +434,6 @@ static struct ata_port_info sil24_port_info[] = { | |||
437 | }, | 434 | }, |
438 | /* sil_3132 */ | 435 | /* sil_3132 */ |
439 | { | 436 | { |
440 | .sht = &sil24_sht, | ||
441 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), | 437 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), |
442 | .pio_mask = 0x1f, /* pio0-4 */ | 438 | .pio_mask = 0x1f, /* pio0-4 */ |
443 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 439 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
@@ -446,7 +442,6 @@ static struct ata_port_info sil24_port_info[] = { | |||
446 | }, | 442 | }, |
447 | /* sil_3131/sil_3531 */ | 443 | /* sil_3131/sil_3531 */ |
448 | { | 444 | { |
449 | .sht = &sil24_sht, | ||
450 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), | 445 | .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), |
451 | .pio_mask = 0x1f, /* pio0-4 */ | 446 | .pio_mask = 0x1f, /* pio0-4 */ |
452 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 447 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
@@ -462,9 +457,9 @@ static int sil24_tag(int tag) | |||
462 | return tag; | 457 | return tag; |
463 | } | 458 | } |
464 | 459 | ||
465 | static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) | 460 | static void sil24_dev_config(struct ata_device *dev) |
466 | { | 461 | { |
467 | void __iomem *port = ap->ioaddr.cmd_addr; | 462 | void __iomem *port = dev->ap->ioaddr.cmd_addr; |
468 | 463 | ||
469 | if (dev->cdb_len == 16) | 464 | if (dev->cdb_len == 16) |
470 | writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); | 465 | writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); |
@@ -924,11 +919,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) | |||
924 | { | 919 | { |
925 | struct ata_port *ap = qc->ap; | 920 | struct ata_port *ap = qc->ap; |
926 | 921 | ||
927 | if (qc->flags & ATA_QCFLAG_FAILED) | ||
928 | qc->err_mask |= AC_ERR_OTHER; | ||
929 | |||
930 | /* make DMA engine forget about the failed command */ | 922 | /* make DMA engine forget about the failed command */ |
931 | if (qc->err_mask) | 923 | if (qc->flags & ATA_QCFLAG_FAILED) |
932 | sil24_init_port(ap); | 924 | sil24_init_port(ap); |
933 | } | 925 | } |
934 | 926 | ||
@@ -964,11 +956,10 @@ static int sil24_port_start(struct ata_port *ap) | |||
964 | return 0; | 956 | return 0; |
965 | } | 957 | } |
966 | 958 | ||
967 | static void sil24_init_controller(struct pci_dev *pdev, int n_ports, | 959 | static void sil24_init_controller(struct ata_host *host) |
968 | unsigned long port_flags, | ||
969 | void __iomem *host_base, | ||
970 | void __iomem *port_base) | ||
971 | { | 960 | { |
961 | void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; | ||
962 | void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; | ||
972 | u32 tmp; | 963 | u32 tmp; |
973 | int i; | 964 | int i; |
974 | 965 | ||
@@ -979,7 +970,7 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports, | |||
979 | writel(0, host_base + HOST_CTRL); | 970 | writel(0, host_base + HOST_CTRL); |
980 | 971 | ||
981 | /* init ports */ | 972 | /* init ports */ |
982 | for (i = 0; i < n_ports; i++) { | 973 | for (i = 0; i < host->n_ports; i++) { |
983 | void __iomem *port = port_base + i * PORT_REGS_SIZE; | 974 | void __iomem *port = port_base + i * PORT_REGS_SIZE; |
984 | 975 | ||
985 | /* Initial PHY setting */ | 976 | /* Initial PHY setting */ |
@@ -993,12 +984,12 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports, | |||
993 | PORT_CS_PORT_RST, | 984 | PORT_CS_PORT_RST, |
994 | PORT_CS_PORT_RST, 10, 100); | 985 | PORT_CS_PORT_RST, 10, 100); |
995 | if (tmp & PORT_CS_PORT_RST) | 986 | if (tmp & PORT_CS_PORT_RST) |
996 | dev_printk(KERN_ERR, &pdev->dev, | 987 | dev_printk(KERN_ERR, host->dev, |
997 | "failed to clear port RST\n"); | 988 | "failed to clear port RST\n"); |
998 | } | 989 | } |
999 | 990 | ||
1000 | /* Configure IRQ WoC */ | 991 | /* Configure IRQ WoC */ |
1001 | if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC) | 992 | if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) |
1002 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); | 993 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); |
1003 | else | 994 | else |
1004 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); | 995 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); |
@@ -1026,18 +1017,17 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports, | |||
1026 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 1017 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
1027 | { | 1018 | { |
1028 | static int printed_version = 0; | 1019 | static int printed_version = 0; |
1029 | struct device *dev = &pdev->dev; | 1020 | struct ata_port_info pi = sil24_port_info[ent->driver_data]; |
1030 | unsigned int board_id = (unsigned int)ent->driver_data; | 1021 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
1031 | struct ata_port_info *pinfo = &sil24_port_info[board_id]; | 1022 | void __iomem * const *iomap; |
1032 | struct ata_probe_ent *probe_ent; | 1023 | struct ata_host *host; |
1033 | void __iomem *host_base; | ||
1034 | void __iomem *port_base; | ||
1035 | int i, rc; | 1024 | int i, rc; |
1036 | u32 tmp; | 1025 | u32 tmp; |
1037 | 1026 | ||
1038 | if (!printed_version++) | 1027 | if (!printed_version++) |
1039 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | 1028 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); |
1040 | 1029 | ||
1030 | /* acquire resources */ | ||
1041 | rc = pcim_enable_device(pdev); | 1031 | rc = pcim_enable_device(pdev); |
1042 | if (rc) | 1032 | if (rc) |
1043 | return rc; | 1033 | return rc; |
@@ -1047,33 +1037,36 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1047 | DRV_NAME); | 1037 | DRV_NAME); |
1048 | if (rc) | 1038 | if (rc) |
1049 | return rc; | 1039 | return rc; |
1040 | iomap = pcim_iomap_table(pdev); | ||
1050 | 1041 | ||
1051 | /* allocate & init probe_ent */ | 1042 | /* apply workaround for completion IRQ loss on PCI-X errata */ |
1052 | probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); | 1043 | if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) { |
1053 | if (!probe_ent) | 1044 | tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL); |
1054 | return -ENOMEM; | 1045 | if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL)) |
1046 | dev_printk(KERN_INFO, &pdev->dev, | ||
1047 | "Applying completion IRQ loss on PCI-X " | ||
1048 | "errata fix\n"); | ||
1049 | else | ||
1050 | pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; | ||
1051 | } | ||
1055 | 1052 | ||
1056 | probe_ent->dev = pci_dev_to_dev(pdev); | 1053 | /* allocate and fill host */ |
1057 | INIT_LIST_HEAD(&probe_ent->node); | 1054 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, |
1055 | SIL24_FLAG2NPORTS(ppi[0]->flags)); | ||
1056 | if (!host) | ||
1057 | return -ENOMEM; | ||
1058 | host->iomap = iomap; | ||
1058 | 1059 | ||
1059 | probe_ent->sht = pinfo->sht; | 1060 | for (i = 0; i < host->n_ports; i++) { |
1060 | probe_ent->port_flags = pinfo->flags; | 1061 | void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE; |
1061 | probe_ent->pio_mask = pinfo->pio_mask; | ||
1062 | probe_ent->mwdma_mask = pinfo->mwdma_mask; | ||
1063 | probe_ent->udma_mask = pinfo->udma_mask; | ||
1064 | probe_ent->port_ops = pinfo->port_ops; | ||
1065 | probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags); | ||
1066 | 1062 | ||
1067 | probe_ent->irq = pdev->irq; | 1063 | host->ports[i]->ioaddr.cmd_addr = port; |
1068 | probe_ent->irq_flags = IRQF_SHARED; | 1064 | host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL; |
1069 | probe_ent->iomap = pcim_iomap_table(pdev); | ||
1070 | 1065 | ||
1071 | host_base = probe_ent->iomap[SIL24_HOST_BAR]; | 1066 | ata_std_ports(&host->ports[i]->ioaddr); |
1072 | port_base = probe_ent->iomap[SIL24_PORT_BAR]; | 1067 | } |
1073 | 1068 | ||
1074 | /* | 1069 | /* configure and activate the device */ |
1075 | * Configure the device | ||
1076 | */ | ||
1077 | if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { | 1070 | if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { |
1078 | rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); | 1071 | rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); |
1079 | if (rc) { | 1072 | if (rc) { |
@@ -1099,36 +1092,11 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1099 | } | 1092 | } |
1100 | } | 1093 | } |
1101 | 1094 | ||
1102 | /* Apply workaround for completion IRQ loss on PCI-X errata */ | 1095 | sil24_init_controller(host); |
1103 | if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) { | ||
1104 | tmp = readl(host_base + HOST_CTRL); | ||
1105 | if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL)) | ||
1106 | dev_printk(KERN_INFO, &pdev->dev, | ||
1107 | "Applying completion IRQ loss on PCI-X " | ||
1108 | "errata fix\n"); | ||
1109 | else | ||
1110 | probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; | ||
1111 | } | ||
1112 | |||
1113 | for (i = 0; i < probe_ent->n_ports; i++) { | ||
1114 | void __iomem *port = port_base + i * PORT_REGS_SIZE; | ||
1115 | |||
1116 | probe_ent->port[i].cmd_addr = port; | ||
1117 | probe_ent->port[i].scr_addr = port + PORT_SCONTROL; | ||
1118 | |||
1119 | ata_std_ports(&probe_ent->port[i]); | ||
1120 | } | ||
1121 | |||
1122 | sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags, | ||
1123 | host_base, port_base); | ||
1124 | 1096 | ||
1125 | pci_set_master(pdev); | 1097 | pci_set_master(pdev); |
1126 | 1098 | return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED, | |
1127 | if (!ata_device_add(probe_ent)) | 1099 | &sil24_sht); |
1128 | return -ENODEV; | ||
1129 | |||
1130 | devm_kfree(dev, probe_ent); | ||
1131 | return 0; | ||
1132 | } | 1100 | } |
1133 | 1101 | ||
1134 | #ifdef CONFIG_PM | 1102 | #ifdef CONFIG_PM |
@@ -1136,7 +1104,6 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) | |||
1136 | { | 1104 | { |
1137 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | 1105 | struct ata_host *host = dev_get_drvdata(&pdev->dev); |
1138 | void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; | 1106 | void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; |
1139 | void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; | ||
1140 | int rc; | 1107 | int rc; |
1141 | 1108 | ||
1142 | rc = ata_pci_device_do_resume(pdev); | 1109 | rc = ata_pci_device_do_resume(pdev); |
@@ -1146,8 +1113,7 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) | |||
1146 | if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) | 1113 | if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) |
1147 | writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL); | 1114 | writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL); |
1148 | 1115 | ||
1149 | sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags, | 1116 | sil24_init_controller(host); |
1150 | host_base, port_base); | ||
1151 | 1117 | ||
1152 | ata_host_resume(host); | 1118 | ata_host_resume(host); |
1153 | 1119 | ||