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;
}
Exemplo n.º 2
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;
}