static void sata_dwc_tf_dump(struct ata_taskfile *tf) { dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:" "0x%lx device: %x\n", tf->command, get_prot_descript(tf->protocol), tf->flags, tf->device); dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x " "lbam: 0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal, tf->lbam, tf->lbah); dev_vdbg(host_pvt.dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x " "hob_lbal: 0x%x hob_lbam: 0x%x hob_lbah: 0x%x\n", tf->hob_feature, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam, tf->hob_lbah); }
static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status) { struct ata_queued_cmd *qc; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); u8 tag = 0; tag = ap->link.active_tag; qc = ata_qc_from_tag(ap, tag); if (!qc) { dev_err(ap->dev, "failed to get qc"); return; } #ifdef DEBUG_NCQ if (tag > 0) { dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s " "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command, get_dma_dir_descript(qc->dma_dir), get_prot_descript(qc->tf.protocol), in_le32(&(hsdev->sata_dwc_regs->dmacr))); } #endif if (ata_is_dma(qc->tf.protocol)) { if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) { dev_err(ap->dev, "%s DMA protocol RX and TX DMA not " "pending dmacr: 0x%08x\n", __func__, in_le32(&(hsdev->sata_dwc_regs->dmacr))); } hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE; sata_dwc_qc_complete(ap, qc, check_status); ap->link.active_tag = ATA_TAG_POISON; } else { sata_dwc_qc_complete(ap, qc, check_status); } }
static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) { u32 sactive; u8 tag = qc->tag; struct ata_port *ap = qc->ap; #ifdef DEBUG_NCQ if (qc->tag > 0 || ap->link.sactive > 1) dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d " "prot=%s ap active_tag=0x%08x ap sactive=0x%08x\n", __func__, ap->print_id, qc->tf.command, ata_get_cmd_descript(qc->tf.command), qc->tag, get_prot_descript(qc->tf.protocol), ap->link.active_tag, ap->link.sactive); #endif if (!ata_is_ncq(qc->tf.protocol)) tag = 0; sata_dwc_qc_prep_by_tag(qc, tag); if (ata_is_ncq(qc->tf.protocol)) { sactive = core_scr_read(SCR_ACTIVE); sactive |= (0x00000001 << tag); core_scr_write(SCR_ACTIVE, sactive); dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x " "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive, sactive); ap->ops->sff_tf_load(ap, &qc->tf); sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag, SATA_DWC_CMD_ISSUED_PEND); } else { ata_sff_qc_issue(qc); } return 0; }
static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) { struct ata_host *host = (struct ata_host *)dev_instance; struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host); struct ata_port *ap; struct ata_queued_cmd *qc; unsigned long flags; u8 status, tag; int handled, num_processed, port = 0; uint intpr, sactive, sactive2, tag_mask; struct sata_dwc_device_port *hsdevp; host_pvt.sata_dwc_sactive_issued = 0; spin_lock_irqsave(&host->lock, flags); intpr = in_le32(&hsdev->sata_dwc_regs->intpr); ap = host->ports[port]; hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr, ap->link.active_tag); if (intpr & SATA_DWC_INTPR_ERR) { sata_dwc_error_intr(ap, hsdev, intpr); handled = 1; goto DONE; } if (intpr & SATA_DWC_INTPR_NEWFP) { clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP); tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr)); dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND) dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag); host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag); qc = ata_qc_from_tag(ap, tag); qc->ap->link.active_tag = tag; sata_dwc_bmdma_start_by_tag(qc, tag); handled = 1; goto DONE; } sactive = core_scr_read(SCR_ACTIVE); tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) { if (ap->link.active_tag == ATA_TAG_POISON) tag = 0; else tag = ap->link.active_tag; qc = ata_qc_from_tag(ap, tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { dev_err(ap->dev, "%s interrupt with no active qc " "qc=%p\n", __func__, qc); ap->ops->sff_check_status(ap); handled = 1; goto DONE; } status = ap->ops->sff_check_status(ap); qc->ap->link.active_tag = tag; hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; if (status & ATA_ERR) { dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status); sata_dwc_qc_complete(ap, qc, 1); handled = 1; goto DONE; } dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n", __func__, get_prot_descript(qc->tf.protocol)); DRVSTILLBUSY: if (ata_is_dma(qc->tf.protocol)) { host_pvt.dma_interrupt_count++; if (hsdevp->dma_pending[tag] == \ SATA_DWC_DMA_PENDING_NONE) { dev_err(ap->dev, "%s: DMA not pending " "intpr=0x%08x status=0x%08x pending" "=%d\n", __func__, intpr, status, hsdevp->dma_pending[tag]); } if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); } else if (ata_is_pio(qc->tf.protocol)) { ata_sff_hsm_move(ap, qc, status, 0); handled = 1; goto DONE; } else { if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) goto DRVSTILLBUSY; } handled = 1; goto DONE; } sactive = core_scr_read(SCR_ACTIVE); tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \ tag_mask > 1) { dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x" "tag_mask=0x%08x\n", __func__, sactive, host_pvt.sata_dwc_sactive_issued, tag_mask); } if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \ (host_pvt.sata_dwc_sactive_issued)) { dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x " "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask" "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued, tag_mask); } status = ap->ops->sff_check_status(ap); dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status); tag = 0; num_processed = 0; while (tag_mask) { num_processed++; while (!(tag_mask & 0x00000001)) { tag++; tag_mask <<= 1; } tag_mask &= (~0x00000001); qc = ata_qc_from_tag(ap, tag); qc->ap->link.active_tag = tag; hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; if (status & ATA_ERR) { dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n", __func__, status); sata_dwc_qc_complete(ap, qc, 1); handled = 1; goto DONE; } dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__, get_prot_descript(qc->tf.protocol)); if (ata_is_dma(qc->tf.protocol)) { host_pvt.dma_interrupt_count++; if (hsdevp->dma_pending[tag] == \ SATA_DWC_DMA_PENDING_NONE) dev_warn(ap->dev, "%s: DMA not pending?\n", __func__); if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); } else { if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) goto STILLBUSY; } continue; STILLBUSY: ap->stats.idle_irq++; dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n", ap->print_id); } sactive2 = core_scr_read(SCR_ACTIVE); if (sactive2 != sactive) { dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2" "=0x%x\n", sactive, sactive2); } handled = 1; DONE: spin_unlock_irqrestore(&host->lock, flags); return IRQ_RETVAL(handled); }
/* * Function : sata_dwc_isr * arguments : irq, void *dev_instance, struct pt_regs *regs * Return value : irqreturn_t - status of IRQ * This Interrupt handler called via port ops registered function. * .irq_handler = sata_dwc_isr */ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) { struct ata_host *host = (struct ata_host *)dev_instance; struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host); struct ata_port *ap; struct ata_queued_cmd *qc; unsigned long flags; u8 status, tag; int handled, num_processed, port = 0; uint intpr, sactive, sactive2, tag_mask; struct sata_dwc_device_port *hsdevp; host_pvt.sata_dwc_sactive_issued = 0; spin_lock_irqsave(&host->lock, flags); /* Read the interrupt register */ intpr = in_le32(&hsdev->sata_dwc_regs->intpr); ap = host->ports[port]; hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr, ap->link.active_tag); /* Check for error interrupt */ if (intpr & SATA_DWC_INTPR_ERR) { sata_dwc_error_intr(ap, hsdev, intpr); handled = 1; goto DONE; } /* Check for DMA SETUP FIS (FP DMA) interrupt */ if (intpr & SATA_DWC_INTPR_NEWFP) { clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP); tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr)); dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND) dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag); host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag); qc = ata_qc_from_tag(ap, tag); /* * Start FP DMA for NCQ command. At this point the tag is the * active tag. It is the tag that matches the command about to * be completed. */ qc->ap->link.active_tag = tag; sata_dwc_bmdma_start_by_tag(qc, tag); handled = 1; goto DONE; } sactive = core_scr_read(SCR_ACTIVE); tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; /* If no sactive issued and tag_mask is zero then this is not NCQ */ if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) { if (ap->link.active_tag == ATA_TAG_POISON) tag = 0; else tag = ap->link.active_tag; qc = ata_qc_from_tag(ap, tag); /* DEV interrupt w/ no active qc? */ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { dev_err(ap->dev, "%s interrupt with no active qc " "qc=%p\n", __func__, qc); ap->ops->sff_check_status(ap); handled = 1; goto DONE; } status = ap->ops->sff_check_status(ap); qc->ap->link.active_tag = tag; hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; if (status & ATA_ERR) { dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status); sata_dwc_qc_complete(ap, qc, 1); handled = 1; goto DONE; } dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n", __func__, get_prot_descript(qc->tf.protocol)); DRVSTILLBUSY: if (ata_is_dma(qc->tf.protocol)) { /* * Each DMA transaction produces 2 interrupts. The DMAC * transfer complete interrupt and the SATA controller * operation done interrupt. The command should be * completed only after both interrupts are seen. */ host_pvt.dma_interrupt_count++; if (hsdevp->dma_pending[tag] == \ SATA_DWC_DMA_PENDING_NONE) { dev_err(ap->dev, "%s: DMA not pending " "intpr=0x%08x status=0x%08x pending" "=%d\n", __func__, intpr, status, hsdevp->dma_pending[tag]); } if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); } else if (ata_is_pio(qc->tf.protocol)) { ata_sff_hsm_move(ap, qc, status, 0); handled = 1; goto DONE; } else { if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) goto DRVSTILLBUSY; } handled = 1; goto DONE; } /* * This is a NCQ command. At this point we need to figure out for which * tags we have gotten a completion interrupt. One interrupt may serve * as completion for more than one operation when commands are queued * (NCQ). We need to process each completed command. */ /* process completed commands */ sactive = core_scr_read(SCR_ACTIVE); tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \ tag_mask > 1) { dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x" "tag_mask=0x%08x\n", __func__, sactive, host_pvt.sata_dwc_sactive_issued, tag_mask); } if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \ (host_pvt.sata_dwc_sactive_issued)) { dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x " "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask" "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued, tag_mask); } /* read just to clear ... not bad if currently still busy */ status = ap->ops->sff_check_status(ap); dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status); tag = 0; num_processed = 0; while (tag_mask) { num_processed++; while (!(tag_mask & 0x00000001)) { tag++; tag_mask <<= 1; } tag_mask &= (~0x00000001); qc = ata_qc_from_tag(ap, tag); /* To be picked up by completion functions */ qc->ap->link.active_tag = tag; hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; /* Let libata/scsi layers handle error */ if (status & ATA_ERR) { dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n", __func__, status); sata_dwc_qc_complete(ap, qc, 1); handled = 1; goto DONE; } /* Process completed command */ dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__, get_prot_descript(qc->tf.protocol)); if (ata_is_dma(qc->tf.protocol)) { host_pvt.dma_interrupt_count++; if (hsdevp->dma_pending[tag] == \ SATA_DWC_DMA_PENDING_NONE) dev_warn(ap->dev, "%s: DMA not pending?\n", __func__); if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); } else { if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) goto STILLBUSY; } continue; STILLBUSY: ap->stats.idle_irq++; dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n", ap->print_id); } /* while tag_mask */ /* * Check to see if any commands completed while we were processing our * initial set of completed commands (read status clears interrupts, * so we might miss a completed command interrupt if one came in while * we were processing --we read status as part of processing a completed * command). */ sactive2 = core_scr_read(SCR_ACTIVE); if (sactive2 != sactive) { dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2" "=0x%x\n", sactive, sactive2); } handled = 1; DONE: spin_unlock_irqrestore(&host->lock, flags); return IRQ_RETVAL(handled); }