static int pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv) { int ret = 0; QDUMP("Waiting for free..."); /* Does not need to be atomic. There's a lock in user space, * but anyhow, this is just for statistics. */ priv->shared->num_wait_free++; while (!priv->free) { u32 rbexhr = gc_readl(priv, REG_GCRBEXHR); ret = wait_event_interruptible_timeout(priv->wait_free, priv->free, HZ*4); if (ret < 0) break; if (ret > 0) continue; if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) { QERROR("TIMEOUT"); ret = -ETIMEDOUT; break; } } QDUMP("done"); return ret; }
static int pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv) { int ret = 0; QDUMP("Waiting for idle..."); /* Does not need to be atomic. There's a lock in user space, * but anyhow, this is just for statistics. */ priv->shared->num_wait_idle++; while (priv->shared->hw_running) { int num = priv->shared->num_interrupts; u32 rbexhr = gc_readl(priv, REG_GCRBEXHR); ret = wait_event_interruptible_timeout(priv->wait_idle, !priv->shared->hw_running, HZ*4); if (ret != 0) break; if (gc_readl(priv, REG_GCRBEXHR) == rbexhr && priv->shared->num_interrupts == num) { QERROR("TIMEOUT"); ret = -ETIMEDOUT; break; } } QDUMP("done"); return ret; }
static irqreturn_t pxa3xx_gcu_handle_irq(int irq, void *ctx) { struct pxa3xx_gcu_priv *priv = ctx; struct pxa3xx_gcu_shared *shared = priv->shared; u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL; QDUMP("-Interrupt"); if (!status) return IRQ_NONE; spin_lock(&priv->spinlock); shared->num_interrupts++; if (status & IE_EEOB) { QDUMP(" [EEOB]"); flush_running(priv); wake_up_all(&priv->wait_free); if (priv->ready) { run_ready(priv); } else { /* There is no more data prepared by the userspace. * Set hw_running = 0 and wait for the next userspace * kick-off */ shared->num_idle++; shared->hw_running = 0; QDUMP(" '-> Idle."); /* set ring buffer length to zero */ gc_writel(priv, REG_GCRBLR, 0); wake_up_all(&priv->wait_idle); } shared->num_done++; } else { QERROR(" [???]"); dump_whole_state(priv); } /* Clear the interrupt */ gc_writel(priv, REG_GCISCR, status); spin_unlock(&priv->spinlock); return IRQ_HANDLED; }
static void dump_whole_state(struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_shared *sh = priv->shared; u32 base = gc_readl(priv, REG_GCRBBR); QDUMP("DUMP"); printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n" "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n", sh->hw_running ? "running" : "idle ", gc_readl(priv, REG_GCISCR), gc_readl(priv, REG_GCRBBR), gc_readl(priv, REG_GCRBLR), (gc_readl(priv, REG_GCRBEXHR) - base) / 4, (gc_readl(priv, REG_GCRBHR) - base) / 4, (gc_readl(priv, REG_GCRBTR) - base) / 4); }