コード例 #1
0
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;
}
コード例 #2
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);
}
コード例 #3
0
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);
}
コード例 #4
0
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);
    }
}
コード例 #5
0
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;
}
コード例 #6
0
/*
 * 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);
}
コード例 #7
0
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);
    }
}
コード例 #8
0
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;
}
コード例 #9
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);
}
コード例 #10
0
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;
}
コード例 #11
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);
}
コード例 #12
0
/*
 * 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;
}