in sata_dwc_460ex.c [463:687]
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;
hsdev->sactive_issued = 0;
spin_lock_irqsave(&host->lock, flags);
/* Read the interrupt register */
intpr = sata_dwc_readl(&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)(sata_dwc_readl(&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);
hsdev->sactive_issued |= qcmd_tag_to_mask(tag);
qc = ata_qc_from_tag(ap, tag);
if (unlikely(!qc)) {
dev_err(ap->dev, "failed to get qc");
handled = 1;
goto DONE;
}
/*
* 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.
*/
trace_ata_bmdma_start(ap, &qc->tf, tag);
qc->ap->link.active_tag = tag;
sata_dwc_bmdma_start_by_tag(qc, tag);
handled = 1;
goto DONE;
}
sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive);
tag_mask = (hsdev->sactive_issued | sactive) ^ sactive;
/* If no sactive issued and tag_mask is zero then this is not NCQ */
if (hsdev->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);
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.
*/
hsdevp->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 ((hsdevp->dma_interrupt_count % 2) == 0)
sata_dwc_dma_xfer_complete(ap);
} 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)))
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 */
sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive);
tag_mask = (hsdev->sactive_issued | sactive) ^ sactive;
if (sactive != 0 || hsdev->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, hsdev->sactive_issued, tag_mask);
}
if ((tag_mask | hsdev->sactive_issued) != hsdev->sactive_issued) {
dev_warn(ap->dev,
"Bad tag mask? sactive=0x%08x sactive_issued=0x%08x tag_mask=0x%08x\n",
sactive, hsdev->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);
if (unlikely(!qc)) {
dev_err(ap->dev, "failed to get qc");
handled = 1;
goto DONE;
}
/* 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);
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)) {
hsdevp->dma_interrupt_count++;
if (hsdevp->dma_pending[tag] == \
SATA_DWC_DMA_PENDING_NONE)
dev_warn(ap->dev, "%s: DMA not pending?\n",
__func__);
if ((hsdevp->dma_interrupt_count % 2) == 0)
sata_dwc_dma_xfer_complete(ap);
} else {
if (unlikely(sata_dwc_qc_complete(ap, qc)))
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).
*/
sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive2);
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);
}