static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, u32 check_status) { u8 status = 0; u32 mask = 0x0; u8 tag = qc->tag; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); host_pvt.sata_dwc_sactive_queued = 0; dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status); if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) dev_err(ap->dev, "TX DMA PENDING\n"); else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) dev_err(ap->dev, "RX DMA PENDING\n"); dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u:" " protocol=%d\n", qc->tf.command, status, ap->print_id, qc->tf.protocol); mask = (~(qcmd_tag_to_mask(tag))); host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \ & mask; host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \ & mask; ata_qc_complete(qc); return 0; }
static void sata_dwc_exec_command_by_tag(struct ata_port *ap, struct ata_taskfile *tf, u8 tag, u32 cmd_issued) { unsigned long flags; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command, ata_get_cmd_descript(tf->command), tag); spin_lock_irqsave(&ap->host->lock, flags); hsdevp->cmd_issued[tag] = cmd_issued; spin_unlock_irqrestore(&ap->host->lock, flags); clear_serror(); ata_sff_exec_command(ap, tf); }
static void sata_dwc_error_intr(struct ata_port *ap, struct sata_dwc_device *hsdev, uint intpr) { struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int err_mask = 0, action = 0; struct ata_queued_cmd *qc; u32 serror; u8 status, tag; u32 err_reg; ata_ehi_clear_desc(ehi); serror = core_scr_read(SCR_ERROR); status = ap->ops->sff_check_status(ap); err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\ low)); tag = ap->link.active_tag; dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x " "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n", __func__, serror, intpr, status, host_pvt.dma_interrupt_count, hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg); clear_serror(); clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR); err_mask |= AC_ERR_HOST_BUS; action |= ATA_EH_RESET; ehi->serror |= serror; ehi->action |= action; qc = ata_qc_from_tag(ap, tag); if (qc) qc->err_mask |= err_mask; else ehi->err_mask |= err_mask; ata_port_abort(ap); }
static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag) { int start_dma; u32 reg, dma_chan; struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc); struct ata_port *ap = qc->ap; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); int dir = qc->dma_dir; dma_chan = hsdevp->dma_chan[tag]; if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) { start_dma = 1; if (dir == DMA_TO_DEVICE) hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX; else hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX; } else { dev_err(ap->dev, "%s: Command not pending cmd_issued=%d " "(tag=%d) DMA NOT started\n", __func__, hsdevp->cmd_issued[tag], tag); start_dma = 0; } dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s " "start_dma? %x\n", __func__, qc, tag, qc->tf.command, get_dma_dir_descript(qc->dma_dir), start_dma); sata_dwc_tf_dump(&(qc->tf)); if (start_dma) { reg = core_scr_read(SCR_ERROR); if (reg & SATA_DWC_SERROR_ERR_BITS) { dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n", __func__, reg); } if (dir == DMA_TO_DEVICE) out_le32(&hsdev->sata_dwc_regs->dmacr, SATA_DWC_DMACR_TXCHEN); else out_le32(&hsdev->sata_dwc_regs->dmacr, SATA_DWC_DMACR_RXCHEN); dma_dwc_xfer_start(dma_chan); } }
static void sata_dwc_port_stop(struct ata_port *ap) { int i; struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id); if (hsdevp && hsdev) { for (i = 0; i < SATA_DWC_QCMD_MAX; i++) { dma_free_coherent(ap->host->dev, SATA_DWC_DMAC_LLI_TBL_SZ, hsdevp->llit[i], hsdevp->llit_dma[i]); } kfree(hsdevp); } ap->private_data = NULL; }
/* * Function : sata_dwc_exec_command_by_tag * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued * Return value : None * This function keeps track of individual command tag ids and calls * ata_exec_command in libata */ static void sata_dwc_exec_command_by_tag(struct ata_port *ap, struct ata_taskfile *tf, u8 tag, u32 cmd_issued) { unsigned long flags; struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command, ata_get_cmd_descript(tf->command), tag); spin_lock_irqsave(&ap->host->lock, flags); hsdevp->cmd_issued[tag] = cmd_issued; spin_unlock_irqrestore(&ap->host->lock, flags); /* * Clear SError before executing a new command. * sata_dwc_scr_write and read can not be used here. Clearing the PM * managed SError register for the disk needs to be done before the * task file is loaded. */ clear_serror(); ata_sff_exec_command(ap, tf); }
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 void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; int dma_chan; struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n", __func__, ap->port_no, get_dma_dir_descript(qc->dma_dir), qc->n_elem); dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag], hsdevp->llit_dma[tag], (void *__iomem)(&hsdev->sata_dwc_regs->\ dmadr), qc->dma_dir); if (dma_chan < 0) { dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n", __func__, dma_chan); return; } hsdevp->dma_chan[tag] = dma_chan; }
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); }
static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) { int chan; u32 tfr_reg, err_reg; unsigned long flags; struct sata_dwc_device *hsdev = (struct sata_dwc_device *)hsdev_instance; struct ata_host *host = (struct ata_host *)hsdev->host; struct ata_port *ap; struct sata_dwc_device_port *hsdevp; u8 tag = 0; unsigned int port = 0; spin_lock_irqsave(&host->lock, flags); ap = host->ports[port]; hsdevp = HSDEVP_FROM_AP(ap); tag = ap->link.active_tag; tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\ .low)); err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\ .low)); dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", tfr_reg, err_reg, hsdevp->dma_pending[tag], port); for (chan = 0; chan < DMA_NUM_CHANS; chan++) { if (tfr_reg & DMA_CHANNEL(chan)) { host_pvt.dma_interrupt_count++; sata_dwc_clear_dmacr(hsdevp, tag); if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) { dev_err(ap->dev, "DMA not pending eot=0x%08x " "err=0x%08x tag=0x%02x pending=%d\n", tfr_reg, err_reg, tag, hsdevp->dma_pending[tag]); } if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ .tfr.low), DMA_CHANNEL(chan)); } if (err_reg & DMA_CHANNEL(chan)) { dev_err(ap->dev, "error interrupt err_reg=0x%08x\n", err_reg); out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ .error.low), DMA_CHANNEL(chan)); } } spin_unlock_irqrestore(&host->lock, flags); return IRQ_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); }
/* * Function: dma_dwc_interrupt * arguments: irq, dev_id, pt_regs * returns channel number if available else -1 * Interrupt Handler for DW AHB SATA DMA */ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) { int chan; u32 tfr_reg, err_reg; unsigned long flags; struct sata_dwc_device *hsdev = hsdev_instance; struct ata_host *host = (struct ata_host *)hsdev->host; struct ata_port *ap; struct sata_dwc_device_port *hsdevp; u8 tag = 0; unsigned int port = 0; spin_lock_irqsave(&host->lock, flags); ap = host->ports[port]; hsdevp = HSDEVP_FROM_AP(ap); tag = ap->link.active_tag; tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\ .low)); err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\ .low)); dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", tfr_reg, err_reg, hsdevp->dma_pending[tag], port); chan = host_pvt.dma_channel; if (chan >= 0) { /* Check for end-of-transfer interrupt. */ if (tfr_reg & DMA_CHANNEL(chan)) { /* * Each DMA command produces 2 interrupts. Only * complete the command after both interrupts have been * seen. (See sata_dwc_isr()) */ host_pvt.dma_interrupt_count++; sata_dwc_clear_dmacr(hsdevp, tag); if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) { dev_err(ap->dev, "DMA not pending eot=0x%08x " "err=0x%08x tag=0x%02x pending=%d\n", tfr_reg, err_reg, tag, hsdevp->dma_pending[tag]); } if ((host_pvt.dma_interrupt_count % 2) == 0) sata_dwc_dma_xfer_complete(ap, 1); /* Clear the interrupt */ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ .tfr.low), DMA_CHANNEL(chan)); } /* Check for error interrupt. */ if (err_reg & DMA_CHANNEL(chan)) { /* TODO Need error handler ! */ dev_err(ap->dev, "error interrupt err_reg=0x%08x\n", err_reg); /* Clear the interrupt. */ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ .error.low), DMA_CHANNEL(chan)); } } spin_unlock_irqrestore(&host->lock, flags); return IRQ_HANDLED; }