static int vmw_fifo_wait(struct vmw_private *dev_priv, uint32_t bytes, bool interruptible, unsigned long timeout) { long ret = 1L; unsigned long irq_flags; if (likely(!vmw_fifo_is_full(dev_priv, bytes))) return 0; vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL); if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return vmw_fifo_wait_noirq(dev_priv, bytes, interruptible, timeout); mutex_lock(&dev_priv->hw_mutex); if (atomic_add_return(1, &dev_priv->fifo_queue_waiters) > 0) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); outl(SVGA_IRQFLAG_FIFO_PROGRESS, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); dev_priv->irq_mask |= SVGA_IRQFLAG_FIFO_PROGRESS; vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } mutex_unlock(&dev_priv->hw_mutex); if (interruptible) ret = wait_event_interruptible_timeout (dev_priv->fifo_queue, !vmw_fifo_is_full(dev_priv, bytes), timeout); else ret = wait_event_timeout (dev_priv->fifo_queue, !vmw_fifo_is_full(dev_priv, bytes), timeout); if (unlikely(ret == 0)) ret = -EBUSY; else if (likely(ret > 0)) ret = 0; mutex_lock(&dev_priv->hw_mutex); if (atomic_dec_and_test(&dev_priv->fifo_queue_waiters)) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); dev_priv->irq_mask &= ~SVGA_IRQFLAG_FIFO_PROGRESS; vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } mutex_unlock(&dev_priv->hw_mutex); return ret; }
static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv, uint32_t bytes, bool interruptible, unsigned long timeout) { int ret = 0; unsigned long end_jiffies = GetTimerTicks() + timeout; DEFINE_WAIT(__wait); DRM_INFO("Fifo wait noirq.\n"); for (;;) { // prepare_to_wait(&dev_priv->fifo_queue, &__wait, // (interruptible) ? // TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (!vmw_fifo_is_full(dev_priv, bytes)) break; if (time_after_eq(GetTimerTicks(), end_jiffies)) { ret = -EBUSY; DRM_ERROR("SVGA device lockup.\n"); break; } delay(1); } // finish_wait(&dev_priv->fifo_queue, &__wait); wake_up_all(&dev_priv->fifo_queue); DRM_INFO("Fifo noirq exit.\n"); return ret; }
static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv, uint32_t bytes, bool interruptible, unsigned long timeout) { int ret = 0; unsigned long end_jiffies = jiffies + timeout; DEFINE_WAIT(__wait); DRM_INFO("Fifo wait noirq.\n"); for (;;) { prepare_to_wait(&dev_priv->fifo_queue, &__wait, (interruptible) ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (!vmw_fifo_is_full(dev_priv, bytes)) break; if (time_after_eq(jiffies, end_jiffies)) { ret = -EBUSY; DRM_ERROR("SVGA device lockup.\n"); break; } schedule_timeout(1); if (interruptible && signal_pending(current)) { ret = -ERESTARTSYS; break; } } finish_wait(&dev_priv->fifo_queue, &__wait); wake_up_all(&dev_priv->fifo_queue); DRM_INFO("Fifo noirq exit.\n"); return ret; }
/** * Reserve @bytes number of bytes in the fifo. * * This function will return NULL (error) on two conditions: * If it timeouts waiting for fifo space, or if @bytes is larger than the * available fifo space. * * Returns: * Pointer to the fifo, or null on error (possible hardware hang). */ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t max; uint32_t min; uint32_t next_cmd; uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; int ret; mutex_lock(&fifo_state->fifo_mutex); max = ioread32(fifo_mem + SVGA_FIFO_MAX); min = ioread32(fifo_mem + SVGA_FIFO_MIN); next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD); if (unlikely(bytes >= (max - min))) goto out_err; BUG_ON(fifo_state->reserved_size != 0); BUG_ON(fifo_state->dynamic_buffer != NULL); fifo_state->reserved_size = bytes; while (1) { uint32_t stop = ioread32(fifo_mem + SVGA_FIFO_STOP); bool need_bounce = false; bool reserve_in_place = false; if (next_cmd >= stop) { if (likely((next_cmd + bytes < max || (next_cmd + bytes == max && stop > min)))) reserve_in_place = true; else if (vmw_fifo_is_full(dev_priv, bytes)) { ret = vmw_fifo_wait(dev_priv, bytes, false, 3 * HZ); if (unlikely(ret != 0)) goto out_err; } else need_bounce = true; } else { if (likely((next_cmd + bytes < stop))) reserve_in_place = true; else { ret = vmw_fifo_wait(dev_priv, bytes, false, 3 * HZ); if (unlikely(ret != 0)) goto out_err; } } if (reserve_in_place) { if (reserveable || bytes <= sizeof(uint32_t)) { fifo_state->using_bounce_buffer = false; if (reserveable) iowrite32(bytes, fifo_mem + SVGA_FIFO_RESERVED); return fifo_mem + (next_cmd >> 2); } else { need_bounce = true; } }