aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-06-25 09:03:34 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:03 -0400
commit1aadf5c3bbbbb0db09dcb5aa26c61326e0d3e9e7 (patch)
tree6aff1f6dc2761f85488be2ed2be5e7f4c92c907c
parentd9027470b88631d0956ac37cdadfdeb9cdcf2c99 (diff)
libata: always use ata_qc_complete_multiple() for NCQ command completions
Currently, sata_fsl, mv and nv call ata_qc_complete() multiple times from their interrupt handlers to indicate completion of NCQ commands. This limits the visibility the libata core layer has into how commands are being executed and completed, which is necessary to support IRQ expecting in generic way. libata already has an interface to complete multiple commands at once - ata_qc_complete_multiple() which ahci and sata_sil24 already use. This patch updates the three drivers to use ata_qc_complete_multiple() too and updates comments on ata_qc_complete[_multiple]() regarding their usages with NCQ completions. This change not only provides better visibility into command execution to the core layer but also simplifies low level drivers. * sata_fsl: It already builds done_mask. Conversion is straight forward. * sata_mv: mv_process_crpb_response() no longer checks for illegal completions, it just returns whether the tag is completed or not. mv_process_crpb_entries() builds done_mask from it and passes it to ata_qc_complete_multiple() which will check for illegal completions. * sata_nv adma: Similar to sata_mv. nv_adma_check_cpb() now just returns the tag status and nv_adma_interrupt() builds done_mask from it and passes it to ata_qc_complete_multiple(). * sata_nv swncq: It already builds done_mask. Drop unnecessary illegal transition checks and call ata_qc_complete_multiple(). In the long run, it might be a good idea to make ata_qc_complete() whine if called when multiple NCQ commands are in flight. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Ashish Kalra <ashish.kalra@freescale.com> Cc: Saeed Bishara <saeed@marvell.com> Cc: Mark Lord <liml@rtr.ca> Cc: Robert Hancock <hancockr@shaw.ca> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/libata-core.c13
-rw-r--r--drivers/ata/sata_fsl.c8
-rw-r--r--drivers/ata/sata_mv.c25
-rw-r--r--drivers/ata/sata_nv.c57
4 files changed, 38 insertions, 65 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 4012b33e8b8a..92cd5f375b8f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4943,8 +4943,13 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
4943 * ata_qc_complete - Complete an active ATA command 4943 * ata_qc_complete - Complete an active ATA command
4944 * @qc: Command to complete 4944 * @qc: Command to complete
4945 * 4945 *
4946 * Indicate to the mid and upper layers that an ATA 4946 * Indicate to the mid and upper layers that an ATA command has
4947 * command has completed, with either an ok or not-ok status. 4947 * completed, with either an ok or not-ok status.
4948 *
4949 * Refrain from calling this function multiple times when
4950 * successfully completing multiple NCQ commands.
4951 * ata_qc_complete_multiple() should be used instead, which will
4952 * properly update IRQ expect state.
4948 * 4953 *
4949 * LOCKING: 4954 * LOCKING:
4950 * spin_lock_irqsave(host lock) 4955 * spin_lock_irqsave(host lock)
@@ -5037,6 +5042,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
5037 * requests normally. ap->qc_active and @qc_active is compared 5042 * requests normally. ap->qc_active and @qc_active is compared
5038 * and commands are completed accordingly. 5043 * and commands are completed accordingly.
5039 * 5044 *
5045 * Always use this function when completing multiple NCQ commands
5046 * from IRQ handlers instead of calling ata_qc_complete()
5047 * multiple times to keep IRQ expect status properly in sync.
5048 *
5040 * LOCKING: 5049 * LOCKING:
5041 * spin_lock_irqsave(host lock) 5050 * spin_lock_irqsave(host lock)
5042 * 5051 *
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 7325f77480dc..1440dc0af242 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1137,17 +1137,13 @@ static void sata_fsl_host_intr(struct ata_port *ap)
1137 ioread32(hcr_base + CE)); 1137 ioread32(hcr_base + CE));
1138 1138
1139 for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) { 1139 for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
1140 if (done_mask & (1 << i)) { 1140 if (done_mask & (1 << i))
1141 qc = ata_qc_from_tag(ap, i);
1142 if (qc) {
1143 ata_qc_complete(qc);
1144 }
1145 DPRINTK 1141 DPRINTK
1146 ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n", 1142 ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
1147 i, ioread32(hcr_base + CC), 1143 i, ioread32(hcr_base + CC),
1148 ioread32(hcr_base + CA)); 1144 ioread32(hcr_base + CA));
1149 }
1150 } 1145 }
1146 ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
1151 return; 1147 return;
1152 1148
1153 } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) { 1149 } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a9fd9709c262..bf74a36d3cc3 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -2743,18 +2743,11 @@ static void mv_err_intr(struct ata_port *ap)
2743 } 2743 }
2744} 2744}
2745 2745
2746static void mv_process_crpb_response(struct ata_port *ap, 2746static bool mv_process_crpb_response(struct ata_port *ap,
2747 struct mv_crpb *response, unsigned int tag, int ncq_enabled) 2747 struct mv_crpb *response, unsigned int tag, int ncq_enabled)
2748{ 2748{
2749 u8 ata_status; 2749 u8 ata_status;
2750 u16 edma_status = le16_to_cpu(response->flags); 2750 u16 edma_status = le16_to_cpu(response->flags);
2751 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
2752
2753 if (unlikely(!qc)) {
2754 ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
2755 __func__, tag);
2756 return;
2757 }
2758 2751
2759 /* 2752 /*
2760 * edma_status from a response queue entry: 2753 * edma_status from a response queue entry:
@@ -2768,13 +2761,14 @@ static void mv_process_crpb_response(struct ata_port *ap,
2768 * Error will be seen/handled by 2761 * Error will be seen/handled by
2769 * mv_err_intr(). So do nothing at all here. 2762 * mv_err_intr(). So do nothing at all here.
2770 */ 2763 */
2771 return; 2764 return false;
2772 } 2765 }
2773 } 2766 }
2774 ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT; 2767 ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
2775 if (!ac_err_mask(ata_status)) 2768 if (!ac_err_mask(ata_status))
2776 ata_qc_complete(qc); 2769 return true;
2777 /* else: leave it for mv_err_intr() */ 2770 /* else: leave it for mv_err_intr() */
2771 return false;
2778} 2772}
2779 2773
2780static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp) 2774static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
@@ -2783,6 +2777,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
2783 struct mv_host_priv *hpriv = ap->host->private_data; 2777 struct mv_host_priv *hpriv = ap->host->private_data;
2784 u32 in_index; 2778 u32 in_index;
2785 bool work_done = false; 2779 bool work_done = false;
2780 u32 done_mask = 0;
2786 int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN); 2781 int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
2787 2782
2788 /* Get the hardware queue position index */ 2783 /* Get the hardware queue position index */
@@ -2803,15 +2798,19 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
2803 /* Gen II/IIE: get command tag from CRPB entry */ 2798 /* Gen II/IIE: get command tag from CRPB entry */
2804 tag = le16_to_cpu(response->id) & 0x1f; 2799 tag = le16_to_cpu(response->id) & 0x1f;
2805 } 2800 }
2806 mv_process_crpb_response(ap, response, tag, ncq_enabled); 2801 if (mv_process_crpb_response(ap, response, tag, ncq_enabled))
2802 done_mask |= 1 << tag;
2807 work_done = true; 2803 work_done = true;
2808 } 2804 }
2809 2805
2810 /* Update the software queue position index in hardware */ 2806 if (work_done) {
2811 if (work_done) 2807 ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
2808
2809 /* Update the software queue position index in hardware */
2812 writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | 2810 writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
2813 (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT), 2811 (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
2814 port_mmio + EDMA_RSP_Q_OUT_PTR); 2812 port_mmio + EDMA_RSP_Q_OUT_PTR);
2813 }
2815} 2814}
2816 2815
2817static void mv_port_intr(struct ata_port *ap, u32 port_cause) 2816static void mv_port_intr(struct ata_port *ap, u32 port_cause)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index cb89ef8d99d9..7254e255fd78 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
873 ata_port_freeze(ap); 873 ata_port_freeze(ap);
874 else 874 else
875 ata_port_abort(ap); 875 ata_port_abort(ap);
876 return 1; 876 return -1;
877 } 877 }
878 878
879 if (likely(flags & NV_CPB_RESP_DONE)) { 879 if (likely(flags & NV_CPB_RESP_DONE))
880 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); 880 return 1;
881 VPRINTK("CPB flags done, flags=0x%x\n", flags);
882 if (likely(qc)) {
883 DPRINTK("Completing qc from tag %d\n", cpb_num);
884 ata_qc_complete(qc);
885 } else {
886 struct ata_eh_info *ehi = &ap->link.eh_info;
887 /* Notifier bits set without a command may indicate the drive
888 is misbehaving. Raise host state machine violation on this
889 condition. */
890 ata_port_printk(ap, KERN_ERR,
891 "notifier for tag %d with no cmd?\n",
892 cpb_num);
893 ehi->err_mask |= AC_ERR_HSM;
894 ehi->action |= ATA_EH_RESET;
895 ata_port_freeze(ap);
896 return 1;
897 }
898 }
899 return 0; 881 return 0;
900} 882}
901 883
@@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
1018 NV_ADMA_STAT_CPBERR | 1000 NV_ADMA_STAT_CPBERR |
1019 NV_ADMA_STAT_CMD_COMPLETE)) { 1001 NV_ADMA_STAT_CMD_COMPLETE)) {
1020 u32 check_commands = notifier_clears[i]; 1002 u32 check_commands = notifier_clears[i];
1003 u32 done_mask = 0;
1021 int pos, rc; 1004 int pos, rc;
1022 1005
1023 if (status & NV_ADMA_STAT_CPBERR) {