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: 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; }