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);
}
예제 #5
0
/*
 * 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);
}