dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] drm/vmwgfx: Replace iowrite/ioread with volatile memory accesses
@ 2015-10-30  9:42 Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet Thomas Hellstrom
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Thomas Hellstrom @ 2015-10-30  9:42 UTC (permalink / raw)
  To: dri-devel; +Cc: Thomas Hellstrom

Now that we use memremap instead of ioremap, Use WRITE_ONCE / READ_ONCE
instead of iowrite / ioread.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |  14 ++---
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h   |  28 ++++++++-
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c |  24 ++++----
 drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c  | 109 ++++++++++++++++------------------
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |  16 ++---
 drivers/gpu/drm/vmwgfx/vmwgfx_irq.c   |   9 +--
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c   |  23 +++----
 7 files changed, 118 insertions(+), 105 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index bee0a45..d1c34ab 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -752,14 +752,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 	ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
 	dev_priv->active_master = &dev_priv->fbdev_master;
 
-	/*
-	 * Force __iomem for this mapping until the implied compiler
-	 * barriers and {READ|WRITE}_ONCE semantics from the
-	 * io{read|write}32() accessors can be replaced with explicit
-	 * barriers.
-	 */
-	dev_priv->mmio_virt = (void __iomem *) memremap(dev_priv->mmio_start,
-					    dev_priv->mmio_size, MEMREMAP_WB);
+	dev_priv->mmio_virt = memremap(dev_priv->mmio_start,
+				       dev_priv->mmio_size, MEMREMAP_WB);
 
 	if (unlikely(dev_priv->mmio_virt == NULL)) {
 		ret = -ENOMEM;
@@ -913,7 +907,7 @@ out_no_irq:
 out_no_device:
 	ttm_object_device_release(&dev_priv->tdev);
 out_err4:
-	memunmap((void __force *) dev_priv->mmio_virt);
+	memunmap(dev_priv->mmio_virt);
 out_err3:
 	vmw_ttm_global_release(dev_priv);
 out_err0:
@@ -964,7 +958,7 @@ static int vmw_driver_unload(struct drm_device *dev)
 		pci_release_regions(dev->pdev);
 
 	ttm_object_device_release(&dev_priv->tdev);
-	memunmap((void __force *) dev_priv->mmio_virt);
+	memunmap(dev_priv->mmio_virt);
 	if (dev_priv->ctx.staged_bindings)
 		vmw_binding_state_free(dev_priv->ctx.staged_bindings);
 	vmw_ttm_global_release(dev_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index a613bd4..198c8b1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -375,7 +375,7 @@ struct vmw_private {
 	uint32_t stdu_max_height;
 	uint32_t initial_width;
 	uint32_t initial_height;
-	u32 __iomem *mmio_virt;
+	u32 *mmio_virt;
 	uint32_t capabilities;
 	uint32_t max_gmr_ids;
 	uint32_t max_gmr_pages;
@@ -1206,4 +1206,30 @@ static inline void vmw_fifo_resource_dec(struct vmw_private *dev_priv)
 {
 	atomic_dec(&dev_priv->num_fifo_resources);
 }
+
+/**
+ * vmw_mmio_read - Perform a MMIO read from volatile memory
+ *
+ * @addr: The address to read from
+ *
+ * This function is intended to be equivalent to ioread32() on
+ * memremap'd memory, but without byteswapping.
+ */
+static inline u32 vmw_mmio_read(u32 *addr)
+{
+	return READ_ONCE(*addr);
+}
+
+/**
+ * vmw_mmio_write - Perform a MMIO write to volatile memory
+ *
+ * @addr: The address to write to
+ *
+ * This function is intended to be equivalent to iowrite32 on
+ * memremap'd memory, but without byteswapping.
+ */
+static inline void vmw_mmio_write(u32 value, u32 *addr)
+{
+	WRITE_ONCE(*addr, value);
+}
 #endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 567dded..8e689b4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -142,8 +142,8 @@ static bool vmw_fence_enable_signaling(struct fence *f)
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
 	struct vmw_private *dev_priv = fman->dev_priv;
 
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-	u32 seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+	u32 *fifo_mem = dev_priv->mmio_virt;
+	u32 seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
 	if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
 		return false;
 
@@ -386,14 +386,14 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
 				      u32 passed_seqno)
 {
 	u32 goal_seqno;
-	u32 __iomem *fifo_mem;
+	u32 *fifo_mem;
 	struct vmw_fence_obj *fence;
 
 	if (likely(!fman->seqno_valid))
 		return false;
 
 	fifo_mem = fman->dev_priv->mmio_virt;
-	goal_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE_GOAL);
+	goal_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE_GOAL);
 	if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
 		return false;
 
@@ -401,8 +401,8 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
 	list_for_each_entry(fence, &fman->fence_list, head) {
 		if (!list_empty(&fence->seq_passed_actions)) {
 			fman->seqno_valid = true;
-			iowrite32(fence->base.seqno,
-				  fifo_mem + SVGA_FIFO_FENCE_GOAL);
+			vmw_mmio_write(fence->base.seqno,
+				       fifo_mem + SVGA_FIFO_FENCE_GOAL);
 			break;
 		}
 	}
@@ -430,18 +430,18 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
 {
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
 	u32 goal_seqno;
-	u32 __iomem *fifo_mem;
+	u32 *fifo_mem;
 
 	if (fence_is_signaled_locked(&fence->base))
 		return false;
 
 	fifo_mem = fman->dev_priv->mmio_virt;
-	goal_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE_GOAL);
+	goal_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE_GOAL);
 	if (likely(fman->seqno_valid &&
 		   goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
 		return false;
 
-	iowrite32(fence->base.seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
+	vmw_mmio_write(fence->base.seqno, fifo_mem + SVGA_FIFO_FENCE_GOAL);
 	fman->seqno_valid = true;
 
 	return true;
@@ -453,9 +453,9 @@ static void __vmw_fences_update(struct vmw_fence_manager *fman)
 	struct list_head action_list;
 	bool needs_rerun;
 	uint32_t seqno, new_seqno;
-	u32 __iomem *fifo_mem = fman->dev_priv->mmio_virt;
+	u32 *fifo_mem = fman->dev_priv->mmio_virt;
 
-	seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+	seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
 rerun:
 	list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
 		if (seqno - fence->base.seqno < VMW_FENCE_WRAP) {
@@ -477,7 +477,7 @@ rerun:
 
 	needs_rerun = vmw_fence_goal_new_locked(fman, seqno);
 	if (unlikely(needs_rerun)) {
-		new_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+		new_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
 		if (new_seqno != seqno) {
 			seqno = new_seqno;
 			goto rerun;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 80c40c3..0cbaf88 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -36,7 +36,7 @@ struct vmw_temp_set_context {
 
 bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32 *fifo_mem = dev_priv->mmio_virt;
 	uint32_t fifo_min, hwversion;
 	const struct vmw_fifo_state *fifo = &dev_priv->fifo;
 
@@ -60,15 +60,15 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
 	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
 		return false;
 
-	fifo_min = ioread32(fifo_mem  + SVGA_FIFO_MIN);
+	fifo_min = vmw_mmio_read(fifo_mem  + SVGA_FIFO_MIN);
 	if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
 		return false;
 
-	hwversion = ioread32(fifo_mem +
-			     ((fifo->capabilities &
-			       SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
-			      SVGA_FIFO_3D_HWVERSION_REVISED :
-			      SVGA_FIFO_3D_HWVERSION));
+	hwversion = vmw_mmio_read(fifo_mem +
+				  ((fifo->capabilities &
+				    SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
+				   SVGA_FIFO_3D_HWVERSION_REVISED :
+				   SVGA_FIFO_3D_HWVERSION));
 
 	if (hwversion == 0)
 		return false;
@@ -85,13 +85,13 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
 
 bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32  *fifo_mem = dev_priv->mmio_virt;
 	uint32_t caps;
 
 	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
 		return false;
 
-	caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES);
+	caps = vmw_mmio_read(fifo_mem + SVGA_FIFO_CAPABILITIES);
 	if (caps & SVGA_FIFO_CAP_PITCHLOCK)
 		return true;
 
@@ -100,7 +100,7 @@ bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv)
 
 int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32  *fifo_mem = dev_priv->mmio_virt;
 	uint32_t max;
 	uint32_t min;
 
@@ -137,19 +137,19 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 	if (min < PAGE_SIZE)
 		min = PAGE_SIZE;
 
-	iowrite32(min, fifo_mem + SVGA_FIFO_MIN);
-	iowrite32(dev_priv->mmio_size, fifo_mem + SVGA_FIFO_MAX);
+	vmw_mmio_write(min, fifo_mem + SVGA_FIFO_MIN);
+	vmw_mmio_write(dev_priv->mmio_size, fifo_mem + SVGA_FIFO_MAX);
 	wmb();
-	iowrite32(min,  fifo_mem + SVGA_FIFO_NEXT_CMD);
-	iowrite32(min,  fifo_mem + SVGA_FIFO_STOP);
-	iowrite32(0, fifo_mem + SVGA_FIFO_BUSY);
+	vmw_mmio_write(min,  fifo_mem + SVGA_FIFO_NEXT_CMD);
+	vmw_mmio_write(min,  fifo_mem + SVGA_FIFO_STOP);
+	vmw_mmio_write(0, fifo_mem + SVGA_FIFO_BUSY);
 	mb();
 
 	vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1);
 
-	max = ioread32(fifo_mem + SVGA_FIFO_MAX);
-	min = ioread32(fifo_mem  + SVGA_FIFO_MIN);
-	fifo->capabilities = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES);
+	max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX);
+	min = vmw_mmio_read(fifo_mem  + SVGA_FIFO_MIN);
+	fifo->capabilities = vmw_mmio_read(fifo_mem + SVGA_FIFO_CAPABILITIES);
 
 	DRM_INFO("Fifo max 0x%08x min 0x%08x cap 0x%08x\n",
 		 (unsigned int) max,
@@ -157,7 +157,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 		 (unsigned int) fifo->capabilities);
 
 	atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno);
-	iowrite32(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE);
+	vmw_mmio_write(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE);
 	vmw_marker_queue_init(&fifo->marker_queue);
 
 	return 0;
@@ -165,31 +165,23 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 
 void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-	static DEFINE_SPINLOCK(ping_lock);
-	unsigned long irq_flags;
+	u32 *fifo_mem = dev_priv->mmio_virt;
 
-	/*
-	 * The ping_lock is needed because we don't have an atomic
-	 * test-and-set of the SVGA_FIFO_BUSY register.
-	 */
-	spin_lock_irqsave(&ping_lock, irq_flags);
-	if (unlikely(ioread32(fifo_mem + SVGA_FIFO_BUSY) == 0)) {
-		iowrite32(1, fifo_mem + SVGA_FIFO_BUSY);
+	preempt_disable();
+	if (cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0)
 		vmw_write(dev_priv, SVGA_REG_SYNC, reason);
-	}
-	spin_unlock_irqrestore(&ping_lock, irq_flags);
+	preempt_enable();
 }
 
 void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32  *fifo_mem = dev_priv->mmio_virt;
 
 	vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
 	while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0)
 		;
 
-	dev_priv->last_read_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+	dev_priv->last_read_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
 
 	vmw_write(dev_priv, SVGA_REG_CONFIG_DONE,
 		  dev_priv->config_done_state);
@@ -213,11 +205,11 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 
 static bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-	uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX);
-	uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
-	uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
-	uint32_t stop = ioread32(fifo_mem + SVGA_FIFO_STOP);
+	u32  *fifo_mem = dev_priv->mmio_virt;
+	uint32_t max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX);
+	uint32_t next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD);
+	uint32_t min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN);
+	uint32_t stop = vmw_mmio_read(fifo_mem + SVGA_FIFO_STOP);
 
 	return ((max - next_cmd) + (stop - min) <= bytes);
 }
@@ -321,7 +313,7 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
 				    uint32_t bytes)
 {
 	struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32  *fifo_mem = dev_priv->mmio_virt;
 	uint32_t max;
 	uint32_t min;
 	uint32_t next_cmd;
@@ -329,9 +321,9 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
 	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);
+	max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX);
+	min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN);
+	next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD);
 
 	if (unlikely(bytes >= (max - min)))
 		goto out_err;
@@ -342,7 +334,7 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
 	fifo_state->reserved_size = bytes;
 
 	while (1) {
-		uint32_t stop = ioread32(fifo_mem + SVGA_FIFO_STOP);
+		uint32_t stop = vmw_mmio_read(fifo_mem + SVGA_FIFO_STOP);
 		bool need_bounce = false;
 		bool reserve_in_place = false;
 
@@ -376,8 +368,8 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
 				fifo_state->using_bounce_buffer = false;
 
 				if (reserveable)
-					iowrite32(bytes, fifo_mem +
-						  SVGA_FIFO_RESERVED);
+					vmw_mmio_write(bytes, fifo_mem +
+						       SVGA_FIFO_RESERVED);
 				return (void __force *) (fifo_mem +
 							 (next_cmd >> 2));
 			} else {
@@ -427,7 +419,7 @@ void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes,
 }
 
 static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state,
-			      u32 __iomem *fifo_mem,
+			      u32  *fifo_mem,
 			      uint32_t next_cmd,
 			      uint32_t max, uint32_t min, uint32_t bytes)
 {
@@ -439,17 +431,16 @@ static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state,
 	if (bytes < chunk_size)
 		chunk_size = bytes;
 
-	iowrite32(bytes, fifo_mem + SVGA_FIFO_RESERVED);
+	vmw_mmio_write(bytes, fifo_mem + SVGA_FIFO_RESERVED);
 	mb();
-	memcpy_toio(fifo_mem + (next_cmd >> 2), buffer, chunk_size);
+	memcpy(fifo_mem + (next_cmd >> 2), buffer, chunk_size);
 	rest = bytes - chunk_size;
 	if (rest)
-		memcpy_toio(fifo_mem + (min >> 2), buffer + (chunk_size >> 2),
-			    rest);
+		memcpy(fifo_mem + (min >> 2), buffer + (chunk_size >> 2), rest);
 }
 
 static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state,
-			       u32 __iomem *fifo_mem,
+			       u32  *fifo_mem,
 			       uint32_t next_cmd,
 			       uint32_t max, uint32_t min, uint32_t bytes)
 {
@@ -457,12 +448,12 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state,
 	    fifo_state->dynamic_buffer : fifo_state->static_buffer;
 
 	while (bytes > 0) {
-		iowrite32(*buffer++, fifo_mem + (next_cmd >> 2));
+		vmw_mmio_write(*buffer++, fifo_mem + (next_cmd >> 2));
 		next_cmd += sizeof(uint32_t);
 		if (unlikely(next_cmd == max))
 			next_cmd = min;
 		mb();
-		iowrite32(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
+		vmw_mmio_write(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
 		mb();
 		bytes -= sizeof(uint32_t);
 	}
@@ -471,10 +462,10 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state,
 static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
 {
 	struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-	uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD);
-	uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX);
-	uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN);
+	u32  *fifo_mem = dev_priv->mmio_virt;
+	uint32_t next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD);
+	uint32_t max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX);
+	uint32_t min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN);
 	bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
 
 	if (fifo_state->dx)
@@ -507,11 +498,11 @@ static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
 		if (next_cmd >= max)
 			next_cmd -= max - min;
 		mb();
-		iowrite32(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
+		vmw_mmio_write(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD);
 	}
 
 	if (reserveable)
-		iowrite32(0, fifo_mem + SVGA_FIFO_RESERVED);
+		vmw_mmio_write(0, fifo_mem + SVGA_FIFO_RESERVED);
 	mb();
 	up_write(&fifo_state->rwsem);
 	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index a3e3c83..b8c6a03 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -64,7 +64,7 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
 		break;
 	case DRM_VMW_PARAM_FIFO_HW_VERSION:
 	{
-		u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+		u32 *fifo_mem = dev_priv->mmio_virt;
 		const struct vmw_fifo_state *fifo = &dev_priv->fifo;
 
 		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) {
@@ -73,11 +73,11 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
 		}
 
 		param->value =
-			ioread32(fifo_mem +
-				 ((fifo->capabilities &
-				   SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
-				  SVGA_FIFO_3D_HWVERSION_REVISED :
-				  SVGA_FIFO_3D_HWVERSION));
+			vmw_mmio_read(fifo_mem +
+				      ((fifo->capabilities &
+					SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
+				       SVGA_FIFO_3D_HWVERSION_REVISED :
+				       SVGA_FIFO_3D_HWVERSION));
 		break;
 	}
 	case DRM_VMW_PARAM_MAX_SURF_MEMORY:
@@ -179,7 +179,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
 		(struct drm_vmw_get_3d_cap_arg *) data;
 	struct vmw_private *dev_priv = vmw_priv(dev);
 	uint32_t size;
-	u32 __iomem *fifo_mem;
+	u32 *fifo_mem;
 	void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
 	void *bounce;
 	int ret;
@@ -229,7 +229,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
 			goto out_err;
 	} else {
 		fifo_mem = dev_priv->mmio_virt;
-		memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
+		memcpy(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
 	}
 
 	ret = copy_to_user(buffer, bounce, size);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index 9498a5e..ac3eccd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -72,8 +72,8 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno)
 void vmw_update_seqno(struct vmw_private *dev_priv,
 			 struct vmw_fifo_state *fifo_state)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-	uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+	u32 *fifo_mem = dev_priv->mmio_virt;
+	uint32_t seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE);
 
 	if (dev_priv->last_read_seqno != seqno) {
 		dev_priv->last_read_seqno = seqno;
@@ -178,8 +178,9 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
 	}
 	finish_wait(&dev_priv->fence_queue, &__wait);
 	if (ret == 0 && fifo_idle) {
-		u32 __iomem *fifo_mem = dev_priv->mmio_virt;
-		iowrite32(signal_seq, fifo_mem + SVGA_FIFO_FENCE);
+		u32 *fifo_mem = dev_priv->mmio_virt;
+
+		vmw_mmio_write(signal_seq, fifo_mem + SVGA_FIFO_FENCE);
 	}
 	wake_up_all(&dev_priv->fence_queue);
 out_err:
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 03ffab2..a94b24d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -123,14 +123,14 @@ err_unreserve:
 void vmw_cursor_update_position(struct vmw_private *dev_priv,
 				bool show, int x, int y)
 {
-	u32 __iomem *fifo_mem = dev_priv->mmio_virt;
+	u32 *fifo_mem = dev_priv->mmio_virt;
 	uint32_t count;
 
-	iowrite32(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON);
-	iowrite32(x, fifo_mem + SVGA_FIFO_CURSOR_X);
-	iowrite32(y, fifo_mem + SVGA_FIFO_CURSOR_Y);
-	count = ioread32(fifo_mem + SVGA_FIFO_CURSOR_COUNT);
-	iowrite32(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT);
+	vmw_mmio_write(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON);
+	vmw_mmio_write(x, fifo_mem + SVGA_FIFO_CURSOR_X);
+	vmw_mmio_write(y, fifo_mem + SVGA_FIFO_CURSOR_Y);
+	count = vmw_mmio_read(fifo_mem + SVGA_FIFO_CURSOR_COUNT);
+	vmw_mmio_write(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT);
 }
 
 int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
@@ -1155,7 +1155,8 @@ int vmw_kms_write_svga(struct vmw_private *vmw_priv,
 	if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
 		vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch);
 	else if (vmw_fifo_have_pitchlock(vmw_priv))
-		iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
+		vmw_mmio_write(pitch, vmw_priv->mmio_virt +
+			       SVGA_FIFO_PITCHLOCK);
 	vmw_write(vmw_priv, SVGA_REG_WIDTH, width);
 	vmw_write(vmw_priv, SVGA_REG_HEIGHT, height);
 	vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bpp);
@@ -1181,8 +1182,8 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
 		vmw_priv->vga_pitchlock =
 		  vmw_read(vmw_priv, SVGA_REG_PITCHLOCK);
 	else if (vmw_fifo_have_pitchlock(vmw_priv))
-		vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt +
-						   SVGA_FIFO_PITCHLOCK);
+		vmw_priv->vga_pitchlock = vmw_mmio_read(vmw_priv->mmio_virt +
+							SVGA_FIFO_PITCHLOCK);
 
 	if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
 		return 0;
@@ -1230,8 +1231,8 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv)
 		vmw_write(vmw_priv, SVGA_REG_PITCHLOCK,
 			  vmw_priv->vga_pitchlock);
 	else if (vmw_fifo_have_pitchlock(vmw_priv))
-		iowrite32(vmw_priv->vga_pitchlock,
-			  vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
+		vmw_mmio_write(vmw_priv->vga_pitchlock,
+			       vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
 
 	if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
 		return 0;
-- 
2.4.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet
  2015-10-30  9:42 [PATCH 1/4] drm/vmwgfx: Replace iowrite/ioread with volatile memory accesses Thomas Hellstrom
@ 2015-10-30  9:42 ` Thomas Hellstrom
  2015-10-30 10:23   ` Daniel Vetter
  2015-10-30  9:42 ` [PATCH 3/4] drm/vmwgfx: Relax irq locking somewhat Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 4/4] drm/vmwgfx: Rework locking around register accesses Thomas Hellstrom
  2 siblings, 1 reply; 6+ messages in thread
From: Thomas Hellstrom @ 2015-10-30  9:42 UTC (permalink / raw)
  To: dri-devel; +Cc: Thomas Hellstrom

Reduce the time in hardware irq context and hardware irq latency.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 108 ++++++++++++++++++++--------------
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.h |   2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_irq.c   |   6 +-
 3 files changed, 68 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 8e689b4..f40c36e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -47,6 +47,7 @@ struct vmw_fence_manager {
 	bool seqno_valid; /* Protected by @lock, and may not be set to true
 			     without the @goal_irq_mutex held. */
 	unsigned ctx;
+	struct tasklet_struct tasklet;
 };
 
 struct vmw_user_fence {
@@ -81,6 +82,8 @@ struct vmw_event_fence_action {
 	uint32_t *tv_usec;
 };
 
+static void vmw_fence_tasklet(unsigned long data);
+
 static struct vmw_fence_manager *
 fman_from_fence(struct vmw_fence_obj *fence)
 {
@@ -115,12 +118,11 @@ static void vmw_fence_obj_destroy(struct fence *f)
 		container_of(f, struct vmw_fence_obj, base);
 
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
-	unsigned long irq_flags;
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	list_del_init(&fence->head);
 	--fman->num_fence_objects;
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 	fence->destroy(fence);
 }
 
@@ -177,7 +179,6 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
 	struct vmw_private *dev_priv = fman->dev_priv;
 	struct vmwgfx_wait_cb cb;
 	long ret = timeout;
-	unsigned long irq_flags;
 
 	if (likely(vmw_fence_obj_signaled(fence)))
 		return timeout;
@@ -185,7 +186,7 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
 	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
 	vmw_seqno_waiter_add(dev_priv);
 
-	spin_lock_irqsave(f->lock, irq_flags);
+	spin_lock_bh(f->lock);
 
 	if (intr && signal_pending(current)) {
 		ret = -ERESTARTSYS;
@@ -205,11 +206,11 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
 			__set_current_state(TASK_INTERRUPTIBLE);
 		else
 			__set_current_state(TASK_UNINTERRUPTIBLE);
-		spin_unlock_irqrestore(f->lock, irq_flags);
+		spin_unlock_bh(f->lock);
 
 		ret = schedule_timeout(ret);
 
-		spin_lock_irqsave(f->lock, irq_flags);
+		spin_lock_bh(f->lock);
 		if (ret > 0 && intr && signal_pending(current))
 			ret = -ERESTARTSYS;
 	}
@@ -219,7 +220,7 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
 	__set_current_state(TASK_RUNNING);
 
 out:
-	spin_unlock_irqrestore(f->lock, irq_flags);
+	spin_unlock_bh(f->lock);
 
 	vmw_seqno_waiter_remove(dev_priv);
 
@@ -300,21 +301,22 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
 		ttm_round_pot(sizeof(struct vmw_event_fence_action));
 	mutex_init(&fman->goal_irq_mutex);
 	fman->ctx = fence_context_alloc(1);
+	tasklet_init(&fman->tasklet, vmw_fence_tasklet,
+		     (unsigned long) fman);
 
 	return fman;
 }
 
 void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
 {
-	unsigned long irq_flags;
 	bool lists_empty;
 
 	(void) cancel_work_sync(&fman->work);
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	lists_empty = list_empty(&fman->fence_list) &&
 		list_empty(&fman->cleanup_list);
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 
 	BUG_ON(!lists_empty);
 	kfree(fman);
@@ -324,7 +326,6 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
 			      struct vmw_fence_obj *fence, u32 seqno,
 			      void (*destroy) (struct vmw_fence_obj *fence))
 {
-	unsigned long irq_flags;
 	int ret = 0;
 
 	fence_init(&fence->base, &vmw_fence_ops, &fman->lock,
@@ -332,7 +333,7 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
 	INIT_LIST_HEAD(&fence->seq_passed_actions);
 	fence->destroy = destroy;
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	if (unlikely(fman->fifo_down)) {
 		ret = -EBUSY;
 		goto out_unlock;
@@ -341,7 +342,7 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
 	++fman->num_fence_objects;
 
 out_unlock:
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 	return ret;
 
 }
@@ -490,11 +491,9 @@ rerun:
 
 void vmw_fences_update(struct vmw_fence_manager *fman)
 {
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	__vmw_fences_update(fman);
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 }
 
 bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
@@ -694,11 +693,9 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
 
 void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
 {
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	fman->fifo_down = false;
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 }
 
 
@@ -825,10 +822,9 @@ void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
 {
 	struct vmw_event_fence_action *eaction;
 	struct drm_pending_event *event;
-	unsigned long irq_flags;
 
 	while (1) {
-		spin_lock_irqsave(&fman->lock, irq_flags);
+		spin_lock_bh(&fman->lock);
 		if (list_empty(event_list))
 			goto out_unlock;
 		eaction = list_first_entry(event_list,
@@ -837,11 +833,11 @@ void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
 		list_del_init(&eaction->fpriv_head);
 		event = eaction->event;
 		eaction->event = NULL;
-		spin_unlock_irqrestore(&fman->lock, irq_flags);
+		spin_unlock_bh(&fman->lock);
 		event->destroy(event);
 	}
 out_unlock:
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 }
 
 
@@ -854,7 +850,7 @@ out_unlock:
  * This function is called when the seqno of the fence where @action is
  * attached has passed. It queues the event on the submitter's event list.
  * This function is always called from atomic context, and may be called
- * from irq context.
+ * from tasklet context.
  */
 static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
 {
@@ -863,13 +859,12 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
 	struct drm_device *dev = eaction->dev;
 	struct drm_pending_event *event = eaction->event;
 	struct drm_file *file_priv;
-	unsigned long irq_flags;
 
 	if (unlikely(event == NULL))
 		return;
 
 	file_priv = event->file_priv;
-	spin_lock_irqsave(&dev->event_lock, irq_flags);
+	spin_lock_bh(&dev->event_lock);
 
 	if (likely(eaction->tv_sec != NULL)) {
 		struct timeval tv;
@@ -883,7 +878,7 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
 	list_add_tail(&eaction->event->link, &file_priv->event_list);
 	eaction->event = NULL;
 	wake_up_all(&file_priv->event_wait);
-	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+	spin_unlock_bh(&dev->event_lock);
 }
 
 /**
@@ -900,11 +895,10 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
 	struct vmw_event_fence_action *eaction =
 		container_of(action, struct vmw_event_fence_action, action);
 	struct vmw_fence_manager *fman = fman_from_fence(eaction->fence);
-	unsigned long irq_flags;
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	list_del(&eaction->fpriv_head);
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 
 	vmw_fence_obj_unreference(&eaction->fence);
 	kfree(eaction);
@@ -924,11 +918,10 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
 			      struct vmw_fence_action *action)
 {
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
-	unsigned long irq_flags;
 	bool run_update = false;
 
 	mutex_lock(&fman->goal_irq_mutex);
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 
 	fman->pending_actions[action->type]++;
 	if (fence_is_signaled_locked(&fence->base)) {
@@ -947,7 +940,7 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
 		run_update = vmw_fence_goal_check_locked(fence);
 	}
 
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 
 	if (run_update) {
 		if (!fman->goal_irq_on) {
@@ -985,7 +978,6 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
 	struct vmw_event_fence_action *eaction;
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
 	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
-	unsigned long irq_flags;
 
 	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
 	if (unlikely(eaction == NULL))
@@ -1002,9 +994,9 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
 	eaction->tv_sec = tv_sec;
 	eaction->tv_usec = tv_usec;
 
-	spin_lock_irqsave(&fman->lock, irq_flags);
+	spin_lock_bh(&fman->lock);
 	list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events);
-	spin_unlock_irqrestore(&fman->lock, irq_flags);
+	spin_unlock_bh(&fman->lock);
 
 	vmw_fence_obj_add_action(fence, &eaction->action);
 
@@ -1025,16 +1017,15 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
 	struct vmw_event_fence_pending *event;
 	struct vmw_fence_manager *fman = fman_from_fence(fence);
 	struct drm_device *dev = fman->dev_priv->dev;
-	unsigned long irq_flags;
 	int ret;
 
-	spin_lock_irqsave(&dev->event_lock, irq_flags);
+	spin_lock_bh(&dev->event_lock);
 
 	ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
 	if (likely(ret == 0))
 		file_priv->event_space -= sizeof(event->event);
 
-	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+	spin_unlock_bh(&dev->event_lock);
 
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("Failed to allocate event space for this file.\n");
@@ -1078,9 +1069,9 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
 out_no_queue:
 	event->base.destroy(&event->base);
 out_no_event:
-	spin_lock_irqsave(&dev->event_lock, irq_flags);
+	spin_lock_bh(&dev->event_lock);
 	file_priv->event_space += sizeof(*event);
-	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
+	spin_unlock_bh(&dev->event_lock);
 out_no_space:
 	return ret;
 }
@@ -1172,3 +1163,32 @@ out_no_ref_obj:
 	vmw_fence_obj_unreference(&fence);
 	return ret;
 }
+
+/**
+ * vmw_fence_tasklet - Fence manager tasklet entry point
+ *
+ * @data: The tasklet closure - A pointer to the fence manager cast to an
+ * unsigned long.
+ */
+static void vmw_fence_tasklet(unsigned long data)
+{
+	struct vmw_fence_manager *fman = (struct vmw_fence_manager *) data;
+
+	spin_lock(&fman->lock);
+	__vmw_fences_update(fman);
+	spin_unlock(&fman->lock);
+	wake_up_all(&fman->dev_priv->fence_queue);
+}
+
+/**
+ * vmw_fence_tasklet_schedule - Schedule a fence manager tasklet run
+ *
+ * @fman: Pointer to a fence manager
+ */
+void vmw_fence_tasklet_schedule(struct vmw_fence_manager *fman)
+{
+	if (!fman)
+		return;
+
+	tasklet_schedule(&fman->tasklet);
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
index 8be6c29..e55b2c9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
@@ -124,4 +124,6 @@ extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
 					uint32_t *tv_sec,
 					uint32_t *tv_usec,
 					bool interruptible);
+extern void vmw_fence_tasklet_schedule(struct vmw_fence_manager *fman);
+
 #endif /* _VMWGFX_FENCE_H_ */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index ac3eccd..b0a6e65 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -48,10 +48,8 @@ irqreturn_t vmw_irq_handler(int irq, void *arg)
 		return IRQ_NONE;
 
 	if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
-			     SVGA_IRQFLAG_FENCE_GOAL)) {
-		vmw_fences_update(dev_priv->fman);
-		wake_up_all(&dev_priv->fence_queue);
-	}
+			     SVGA_IRQFLAG_FENCE_GOAL))
+		vmw_fence_tasklet_schedule(dev_priv->fman);
 
 	if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS)
 		wake_up_all(&dev_priv->fifo_queue);
-- 
2.4.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] drm/vmwgfx: Relax irq locking somewhat
  2015-10-30  9:42 [PATCH 1/4] drm/vmwgfx: Replace iowrite/ioread with volatile memory accesses Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet Thomas Hellstrom
@ 2015-10-30  9:42 ` Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 4/4] drm/vmwgfx: Rework locking around register accesses Thomas Hellstrom
  2 siblings, 0 replies; 6+ messages in thread
From: Thomas Hellstrom @ 2015-10-30  9:42 UTC (permalink / raw)
  To: dri-devel; +Cc: Thomas Hellstrom

Relax locking with the goal of reducing the number of locking cycles and
time spent with irqs disabled.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c  |   2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h  |   9 ++-
 drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c |  23 ++------
 drivers/gpu/drm/vmwgfx/vmwgfx_irq.c  | 104 ++++++++++-------------------------
 4 files changed, 39 insertions(+), 99 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index d1c34ab..a09cf85 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -643,7 +643,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 	init_waitqueue_head(&dev_priv->fence_queue);
 	init_waitqueue_head(&dev_priv->fifo_queue);
 	dev_priv->fence_queue_waiters = 0;
-	atomic_set(&dev_priv->fifo_queue_waiters, 0);
+	dev_priv->fifo_queue_waiters = 0;
 
 	dev_priv->used_memory_size = 0;
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 198c8b1..a8ae9df 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -440,13 +440,12 @@ struct vmw_private {
 	spinlock_t waiter_lock;
 	int fence_queue_waiters; /* Protected by waiter_lock */
 	int goal_queue_waiters; /* Protected by waiter_lock */
-	int cmdbuf_waiters; /* Protected by irq_lock */
-	int error_waiters; /* Protected by irq_lock */
-	atomic_t fifo_queue_waiters;
+	int cmdbuf_waiters; /* Protected by waiter_lock */
+	int error_waiters; /* Protected by waiter_lock */
+	int fifo_queue_waiters; /* Protected by waiter_lock */
 	uint32_t last_read_seqno;
-	spinlock_t irq_lock;
 	struct vmw_fence_manager *fman;
-	uint32_t irq_mask;
+	uint32_t irq_mask; /* Updates protected by waiter_lock */
 
 	/*
 	 * Device state
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 0cbaf88..a8baf5f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -252,7 +252,6 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
 			 unsigned long timeout)
 {
 	long ret = 1L;
-	unsigned long irq_flags;
 
 	if (likely(!vmw_fifo_is_full(dev_priv, bytes)))
 		return 0;
@@ -262,16 +261,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
 		return vmw_fifo_wait_noirq(dev_priv, bytes,
 					   interruptible, timeout);
 
-	spin_lock(&dev_priv->waiter_lock);
-	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);
-	}
-	spin_unlock(&dev_priv->waiter_lock);
+	vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,
+			       &dev_priv->fifo_queue_waiters);
 
 	if (interruptible)
 		ret = wait_event_interruptible_timeout
@@ -287,14 +278,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
 	else if (likely(ret > 0))
 		ret = 0;
 
-	spin_lock(&dev_priv->waiter_lock);
-	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);
-	}
-	spin_unlock(&dev_priv->waiter_lock);
+	vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,
+				  &dev_priv->fifo_queue_waiters);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index b0a6e65..12aaed7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -36,15 +36,13 @@ irqreturn_t vmw_irq_handler(int irq, void *arg)
 	struct vmw_private *dev_priv = vmw_priv(dev);
 	uint32_t status, masked_status;
 
-	spin_lock(&dev_priv->irq_lock);
 	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
-	masked_status = status & dev_priv->irq_mask;
-	spin_unlock(&dev_priv->irq_lock);
+	masked_status = status & READ_ONCE(dev_priv->irq_mask);
 
 	if (likely(status))
 		outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 
-	if (!masked_status)
+	if (!status)
 		return IRQ_NONE;
 
 	if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
@@ -188,65 +186,51 @@ out_err:
 	return ret;
 }
 
-void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
+void vmw_generic_waiter_add(struct vmw_private *dev_priv,
+			    u32 flag, int *waiter_count)
 {
-	spin_lock(&dev_priv->waiter_lock);
-	if (dev_priv->fence_queue_waiters++ == 0) {
-		unsigned long irq_flags;
-
-		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-		outl(SVGA_IRQFLAG_ANY_FENCE,
-		     dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
-		dev_priv->irq_mask |= SVGA_IRQFLAG_ANY_FENCE;
+	spin_lock_bh(&dev_priv->waiter_lock);
+	if ((*waiter_count)++ == 0) {
+		outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
+		dev_priv->irq_mask |= flag;
 		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
 	}
-	spin_unlock(&dev_priv->waiter_lock);
+	spin_unlock_bh(&dev_priv->waiter_lock);
 }
 
-void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
+void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
+			       u32 flag, int *waiter_count)
 {
-	spin_lock(&dev_priv->waiter_lock);
-	if (--dev_priv->fence_queue_waiters == 0) {
-		unsigned long irq_flags;
-
-		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-		dev_priv->irq_mask &= ~SVGA_IRQFLAG_ANY_FENCE;
+	spin_lock_bh(&dev_priv->waiter_lock);
+	if (--(*waiter_count) == 0) {
+		dev_priv->irq_mask &= ~flag;
 		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
 	}
-	spin_unlock(&dev_priv->waiter_lock);
+	spin_unlock_bh(&dev_priv->waiter_lock);
 }
 
+void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
+{
+	vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ANY_FENCE,
+			       &dev_priv->fence_queue_waiters);
+}
+
+void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
+{
+	vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_ANY_FENCE,
+				  &dev_priv->fence_queue_waiters);
+}
 
 void vmw_goal_waiter_add(struct vmw_private *dev_priv)
 {
-	spin_lock(&dev_priv->waiter_lock);
-	if (dev_priv->goal_queue_waiters++ == 0) {
-		unsigned long irq_flags;
-
-		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-		outl(SVGA_IRQFLAG_FENCE_GOAL,
-		     dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
-		dev_priv->irq_mask |= SVGA_IRQFLAG_FENCE_GOAL;
-		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
-	}
-	spin_unlock(&dev_priv->waiter_lock);
+	vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+			       &dev_priv->goal_queue_waiters);
 }
 
 void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
 {
-	spin_lock(&dev_priv->waiter_lock);
-	if (--dev_priv->goal_queue_waiters == 0) {
-		unsigned long irq_flags;
-
-		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-		dev_priv->irq_mask &= ~SVGA_IRQFLAG_FENCE_GOAL;
-		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
-	}
-	spin_unlock(&dev_priv->waiter_lock);
+	vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
+				  &dev_priv->goal_queue_waiters);
 }
 
 int vmw_wait_seqno(struct vmw_private *dev_priv,
@@ -303,7 +287,6 @@ void vmw_irq_preinstall(struct drm_device *dev)
 	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
 		return;
 
-	spin_lock_init(&dev_priv->irq_lock);
 	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 	outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 }
@@ -326,30 +309,3 @@ void vmw_irq_uninstall(struct drm_device *dev)
 	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 	outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 }
-
-void vmw_generic_waiter_add(struct vmw_private *dev_priv,
-			    u32 flag, int *waiter_count)
-{
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-	if ((*waiter_count)++ == 0) {
-		outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
-		dev_priv->irq_mask |= flag;
-		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-	}
-	spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
-}
-
-void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
-			       u32 flag, int *waiter_count)
-{
-	unsigned long irq_flags;
-
-	spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
-	if (--(*waiter_count) == 0) {
-		dev_priv->irq_mask &= ~flag;
-		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
-	}
-	spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
-}
-- 
2.4.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] drm/vmwgfx: Rework locking around register accesses
  2015-10-30  9:42 [PATCH 1/4] drm/vmwgfx: Replace iowrite/ioread with volatile memory accesses Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet Thomas Hellstrom
  2015-10-30  9:42 ` [PATCH 3/4] drm/vmwgfx: Relax irq locking somewhat Thomas Hellstrom
@ 2015-10-30  9:42 ` Thomas Hellstrom
  2 siblings, 0 replies; 6+ messages in thread
From: Thomas Hellstrom @ 2015-10-30  9:42 UTC (permalink / raw)
  To: dri-devel; +Cc: Thomas Hellstrom

Relax the required locking to, instead of disabling irqs, disable tasklets.
Allow the caller to perform the locking using utility functions, which
allows the caller to combine a number of register accesses within the
same critical section. Implement this for capability reads and command
buffer submission.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c |   8 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c    |   9 +--
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.h    | 130 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c  |   6 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c   |  40 +++++++---
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c  |  20 ++---
 drivers/gpu/drm/vmwgfx/vmwgfx_irq.c    |   2 +-
 7 files changed, 163 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
index 8a76821..b8d2436 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -290,18 +290,20 @@ void vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header)
  */
 static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header)
 {
-	struct vmw_cmdbuf_man *man = header->man;
+	struct vmw_private *dev_priv = header->man->dev_priv;
 	u32 val;
 
 	if (sizeof(header->handle) > 4)
 		val = (header->handle >> 32);
 	else
 		val = 0;
-	vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val);
+	vmw_hw_lock(dev_priv, true);
+	__vmw_write(dev_priv, SVGA_REG_COMMAND_HIGH, val);
 
 	val = (header->handle & 0xFFFFFFFFULL);
 	val |= header->cb_context & SVGA_CB_CONTEXT_MASK;
-	vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val);
+	__vmw_write(dev_priv, SVGA_REG_COMMAND_LOW, val);
+	vmw_hw_unlock(dev_priv, true);
 
 	return header->cb_header->status;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index a09cf85..2a5496a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -631,7 +631,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 	ttm_lock_init(&dev_priv->reservation_sem);
 	spin_lock_init(&dev_priv->hw_lock);
 	spin_lock_init(&dev_priv->waiter_lock);
-	spin_lock_init(&dev_priv->cap_lock);
 	spin_lock_init(&dev_priv->svga_lock);
 
 	for (i = vmw_res_context; i < vmw_res_max; ++i) {
@@ -854,10 +853,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 	}
 
 	if (dev_priv->has_mob) {
-		spin_lock(&dev_priv->cap_lock);
-		vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX);
-		dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP);
-		spin_unlock(&dev_priv->cap_lock);
+		vmw_hw_lock(dev_priv, true);
+		__vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX);
+		dev_priv->has_dx = !!__vmw_read(dev_priv, SVGA_REG_DEV_CAP);
+		vmw_hw_unlock(dev_priv, true);
 	}
 
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index a8ae9df..f7dcbcc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -385,7 +385,6 @@ struct vmw_private {
 	bool has_gmr;
 	bool has_mob;
 	spinlock_t hw_lock;
-	spinlock_t cap_lock;
 	bool has_dx;
 
 	/*
@@ -546,34 +545,127 @@ static inline struct vmw_master *vmw_master(struct drm_master *master)
 	return (struct vmw_master *) master->driver_priv;
 }
 
-/*
- * The locking here is fine-grained, so that it is performed once
- * for every read- and write operation. This is of course costly, but we
- * don't perform much register access in the timing critical paths anyway.
- * Instead we have the extra benefit of being sure that we don't forget
- * the hw lock around register accesses.
+/**
+ * vmw_hw_lock - Perform necessary locking for register access
+ *
+ * @dev_priv: Pointer to device private structure
+ * @lock_bh: Disable bottom halves. Always set to true unless irqs are disabled.
  */
-static inline void vmw_write(struct vmw_private *dev_priv,
-			     unsigned int offset, uint32_t value)
+static inline void vmw_hw_lock(struct vmw_private *dev_priv,
+			       bool lock_bh)
 {
-	unsigned long irq_flags;
+	if (lock_bh)
+		spin_lock_bh(&dev_priv->hw_lock);
+	else
+		spin_lock(&dev_priv->hw_lock);
+}
 
-	spin_lock_irqsave(&dev_priv->hw_lock, irq_flags);
+/**
+ * vmw_hw_unlock - Perform necessary unlocking after register access
+ *
+ * @dev_priv: Pointer to device private structure
+ * @unlock_bh: Disable bottom halves. Always set to true if it was set to tru
+ * in the corresponding lock.
+ */
+static inline void vmw_hw_unlock(struct vmw_private *dev_priv,
+				 bool unlock_bh)
+{
+	if (unlock_bh)
+		spin_unlock_bh(&dev_priv->hw_lock);
+	else
+		spin_unlock(&dev_priv->hw_lock);
+}
+
+/**
+ * __vmw_write - Write a value to a device register with external locking.
+ *
+ * @dev_priv: Pointer to the device private structure
+ * @offset: Device register offset
+ * @value: Value to write
+ *
+ * Note that the caller must ensure that when calling this function,
+ * @dev_priv::hw_lock must be held and that we're safe against racing
+ * against tasklets.
+ */
+static inline void __vmw_write(struct vmw_private *dev_priv,
+			       unsigned int offset, uint32_t value)
+{
+#ifdef CONFIG_LOCKDEP
+	lockdep_assert_held_once(&dev_priv->hw_lock.rlock);
+	WARN_ON_ONCE(!(in_softirq() || irqs_disabled()));
+#endif
 	outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
 	outl(value, dev_priv->io_start + VMWGFX_VALUE_PORT);
-	spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags);
 }
 
-static inline uint32_t vmw_read(struct vmw_private *dev_priv,
-				unsigned int offset)
+/**
+ * __vmw_read - Read a value from a device register with external locking.
+ *
+ * @dev_priv: Pointer to the device private structure
+ * @offset: Device register offset
+ * @value: Value to write
+ *
+ * Note that the caller must ensure that when calling this function,
+ * @dev_priv::hw_lock is be held and that we're safe against racing
+ * against tasklets.
+ */
+static inline uint32_t __vmw_read(struct vmw_private *dev_priv,
+				  unsigned int offset)
 {
-	unsigned long irq_flags;
 	u32 val;
 
-	spin_lock_irqsave(&dev_priv->hw_lock, irq_flags);
+#ifdef CONFIG_LOCKDEP
+	lockdep_assert_held_once(&dev_priv->hw_lock.rlock);
+	WARN_ON_ONCE(!(in_softirq() || irqs_disabled()));
+#endif
 	outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
 	val = inl(dev_priv->io_start + VMWGFX_VALUE_PORT);
-	spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags);
+
+	return val;
+}
+
+/**
+ * vmw_write - Write a value to a device register
+ *
+ * @dev_priv: Pointer to the device private structure
+ * @offset: Device register offset
+ * @value: Value to write
+ *
+ * This function may not be called when irqs are disabled, since
+ * its call to vmw_hw_unlock will re-enable irqs.
+ */
+static inline void vmw_write(struct vmw_private *dev_priv,
+			     unsigned int offset, uint32_t value)
+{
+#ifdef CONFIG_LOCKDEP
+	WARN_ON_ONCE(irqs_disabled());
+#endif
+	vmw_hw_lock(dev_priv, true);
+	__vmw_write(dev_priv, offset, value);
+	vmw_hw_unlock(dev_priv, true);
+}
+
+/**
+ * vmw_write - Read a value from a device register
+ *
+ * @dev_priv: Pointer to the device private structure
+ * @offset: Device register offset
+ * @value: Value to write
+ *
+ * This function may not be called when irqs are disabled, since
+ * its call to vmw_hw_unlock will re-enable irqs.
+ */
+static inline uint32_t vmw_read(struct vmw_private *dev_priv,
+				unsigned int offset)
+{
+	u32 val;
+
+#ifdef CONFIG_LOCKDEP
+	WARN_ON_ONCE(irqs_disabled());
+#endif
+	vmw_hw_lock(dev_priv, true);
+	val = __vmw_read(dev_priv, offset);
+	vmw_hw_unlock(dev_priv, true);
 
 	return val;
 }
@@ -722,8 +814,8 @@ extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes);
 extern void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes);
 extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
 			       uint32_t *seqno);
-extern void vmw_fifo_ping_host_locked(struct vmw_private *, uint32_t reason);
-extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
+extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason,
+			       bool lock_bh);
 extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
 extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
 extern int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index f40c36e..ac66aad 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -149,7 +149,7 @@ static bool vmw_fence_enable_signaling(struct fence *f)
 	if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
 		return false;
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, false);
 
 	return true;
 }
@@ -183,7 +183,7 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
 	if (likely(vmw_fence_obj_signaled(fence)))
 		return timeout;
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 	vmw_seqno_waiter_add(dev_priv);
 
 	spin_lock_bh(f->lock);
@@ -525,7 +525,7 @@ void vmw_fence_obj_flush(struct vmw_fence_obj *fence)
 {
 	struct vmw_private *dev_priv = fman_from_fence(fence)->dev_priv;
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 }
 
 static void vmw_fence_destroy(struct vmw_fence_obj *fence)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index a8baf5f..a70cc88 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -49,10 +49,10 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
 		if (!dev_priv->has_mob)
 			return false;
 
-		spin_lock(&dev_priv->cap_lock);
-		vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D);
-		result = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
-		spin_unlock(&dev_priv->cap_lock);
+		vmw_hw_lock(dev_priv, true);
+		__vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D);
+		result = __vmw_read(dev_priv, SVGA_REG_DEV_CAP);
+		vmw_hw_unlock(dev_priv, true);
 
 		return (result != 0);
 	}
@@ -163,14 +163,32 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 	return 0;
 }
 
-void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
+/**
+ * vmw_fifo_ping_host - Notify the device that there are device commands
+ * to process
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @reason: A valid reason to ping the host. See device headers.
+ * @lock_bh: Always set to true unless irqs are disabled in which case
+ * it must be set to false.
+ *
+ * Aka the device "doorbell". The device has an optimization that allows
+ * avoiding calling the relatively expensive register write to
+ * SVGA_REG_SYNC if the SVGA_FIFO_BUSY mmio register is set to 1, meaning
+ * that the doorbell has already been called. The SVGA_FIFO_BUSY mmio register
+ * will be cleared by the device when a new write to SVGA_REG_SYNC is needed
+ * to notify the device of pending commands.
+ */
+void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason,
+			bool lock_bh)
 {
 	u32 *fifo_mem = dev_priv->mmio_virt;
 
-	preempt_disable();
-	if (cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0)
-		vmw_write(dev_priv, SVGA_REG_SYNC, reason);
-	preempt_enable();
+	if (cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0) {
+		vmw_hw_lock(dev_priv, lock_bh);
+		__vmw_write(dev_priv, SVGA_REG_SYNC, reason);
+		vmw_hw_unlock(dev_priv, lock_bh);
+	}
 }
 
 void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
@@ -256,7 +274,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
 	if (likely(!vmw_fifo_is_full(dev_priv, bytes)))
 		return 0;
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL, true);
 	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
 		return vmw_fifo_wait_noirq(dev_priv, bytes,
 					   interruptible, timeout);
@@ -490,7 +508,7 @@ static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)
 		vmw_mmio_write(0, fifo_mem + SVGA_FIFO_RESERVED);
 	mb();
 	up_write(&fifo_state->rwsem);
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 	mutex_unlock(&fifo_state->fifo_mutex);
 }
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index b8c6a03..8ce0886 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -159,14 +159,14 @@ static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce,
 		(pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32);
 	compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS;
 
-	spin_lock(&dev_priv->cap_lock);
+	vmw_hw_lock(dev_priv, true);
 	for (i = 0; i < max_size; ++i) {
-		vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
+		__vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
 		compat_cap->pairs[i][0] = i;
 		compat_cap->pairs[i][1] = vmw_mask_multisample
-			(i, vmw_read(dev_priv, SVGA_REG_DEV_CAP));
+			(i, __vmw_read(dev_priv, SVGA_REG_DEV_CAP));
 	}
-	spin_unlock(&dev_priv->cap_lock);
+	vmw_hw_unlock(dev_priv, true);
 
 	return 0;
 }
@@ -216,13 +216,13 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
 		if (num > SVGA3D_DEVCAP_MAX)
 			num = SVGA3D_DEVCAP_MAX;
 
-		spin_lock(&dev_priv->cap_lock);
+		vmw_hw_lock(dev_priv, true);
 		for (i = 0; i < num; ++i) {
-			vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
+			__vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
 			*bounce32++ = vmw_mask_multisample
-				(i, vmw_read(dev_priv, SVGA_REG_DEV_CAP));
+				(i, __vmw_read(dev_priv, SVGA_REG_DEV_CAP));
 		}
-		spin_unlock(&dev_priv->cap_lock);
+		vmw_hw_unlock(dev_priv, true);
 	} else if (gb_objects) {
 		ret = vmw_fill_compat_cap(dev_priv, bounce, size);
 		if (unlikely(ret != 0))
@@ -420,7 +420,7 @@ unsigned int vmw_fops_poll(struct file *filp, struct poll_table_struct *wait)
 	struct vmw_private *dev_priv =
 		vmw_priv(file_priv->minor->dev);
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 	return drm_poll(filp, wait);
 }
 
@@ -443,6 +443,6 @@ ssize_t vmw_fops_read(struct file *filp, char __user *buffer,
 	struct vmw_private *dev_priv =
 		vmw_priv(file_priv->minor->dev);
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 	return drm_read(filp, buffer, count, offset);
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index 12aaed7..af6970b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -246,7 +246,7 @@ int vmw_wait_seqno(struct vmw_private *dev_priv,
 	if (likely(vmw_seqno_passed(dev_priv, seqno)))
 		return 0;
 
-	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC, true);
 
 	if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE))
 		return vmw_fallback_wait(dev_priv, lazy, true, seqno,
-- 
2.4.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet
  2015-10-30  9:42 ` [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet Thomas Hellstrom
@ 2015-10-30 10:23   ` Daniel Vetter
  2015-10-30 11:08     ` Thomas Hellstrom
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Vetter @ 2015-10-30 10:23 UTC (permalink / raw)
  To: Thomas Hellstrom; +Cc: dri-devel

On Fri, Oct 30, 2015 at 02:42:44AM -0700, Thomas Hellstrom wrote:
> Reduce the time in hardware irq context and hardware irq latency.
> 
> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
> Reviewed-by: Sinclair Yeh <syeh@vmware.com>
> ---
>  drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 108 ++++++++++++++++++++--------------
>  drivers/gpu/drm/vmwgfx/vmwgfx_fence.h |   2 +
>  drivers/gpu/drm/vmwgfx/vmwgfx_irq.c   |   6 +-
>  3 files changed, 68 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> index 8e689b4..f40c36e 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> @@ -47,6 +47,7 @@ struct vmw_fence_manager {
>  	bool seqno_valid; /* Protected by @lock, and may not be set to true
>  			     without the @goal_irq_mutex held. */
>  	unsigned ctx;
> +	struct tasklet_struct tasklet;

Bottom halves are super-deprecated except for giant existing users like
networking. I think the recommended way to do this is to either use
threaded interrupts or work-queues. The reason for that seems to be that
locking is funky around them, which is a major pain for RT. And RT is
going mainline now for real.
-Daniel

>  };
>  
>  struct vmw_user_fence {
> @@ -81,6 +82,8 @@ struct vmw_event_fence_action {
>  	uint32_t *tv_usec;
>  };
>  
> +static void vmw_fence_tasklet(unsigned long data);
> +
>  static struct vmw_fence_manager *
>  fman_from_fence(struct vmw_fence_obj *fence)
>  {
> @@ -115,12 +118,11 @@ static void vmw_fence_obj_destroy(struct fence *f)
>  		container_of(f, struct vmw_fence_obj, base);
>  
>  	struct vmw_fence_manager *fman = fman_from_fence(fence);
> -	unsigned long irq_flags;
>  
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	list_del_init(&fence->head);
>  	--fman->num_fence_objects;
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  	fence->destroy(fence);
>  }
>  
> @@ -177,7 +179,6 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
>  	struct vmw_private *dev_priv = fman->dev_priv;
>  	struct vmwgfx_wait_cb cb;
>  	long ret = timeout;
> -	unsigned long irq_flags;
>  
>  	if (likely(vmw_fence_obj_signaled(fence)))
>  		return timeout;
> @@ -185,7 +186,7 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
>  	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
>  	vmw_seqno_waiter_add(dev_priv);
>  
> -	spin_lock_irqsave(f->lock, irq_flags);
> +	spin_lock_bh(f->lock);
>  
>  	if (intr && signal_pending(current)) {
>  		ret = -ERESTARTSYS;
> @@ -205,11 +206,11 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
>  			__set_current_state(TASK_INTERRUPTIBLE);
>  		else
>  			__set_current_state(TASK_UNINTERRUPTIBLE);
> -		spin_unlock_irqrestore(f->lock, irq_flags);
> +		spin_unlock_bh(f->lock);
>  
>  		ret = schedule_timeout(ret);
>  
> -		spin_lock_irqsave(f->lock, irq_flags);
> +		spin_lock_bh(f->lock);
>  		if (ret > 0 && intr && signal_pending(current))
>  			ret = -ERESTARTSYS;
>  	}
> @@ -219,7 +220,7 @@ static long vmw_fence_wait(struct fence *f, bool intr, signed long timeout)
>  	__set_current_state(TASK_RUNNING);
>  
>  out:
> -	spin_unlock_irqrestore(f->lock, irq_flags);
> +	spin_unlock_bh(f->lock);
>  
>  	vmw_seqno_waiter_remove(dev_priv);
>  
> @@ -300,21 +301,22 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
>  		ttm_round_pot(sizeof(struct vmw_event_fence_action));
>  	mutex_init(&fman->goal_irq_mutex);
>  	fman->ctx = fence_context_alloc(1);
> +	tasklet_init(&fman->tasklet, vmw_fence_tasklet,
> +		     (unsigned long) fman);
>  
>  	return fman;
>  }
>  
>  void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
>  {
> -	unsigned long irq_flags;
>  	bool lists_empty;
>  
>  	(void) cancel_work_sync(&fman->work);
>  
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	lists_empty = list_empty(&fman->fence_list) &&
>  		list_empty(&fman->cleanup_list);
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  
>  	BUG_ON(!lists_empty);
>  	kfree(fman);
> @@ -324,7 +326,6 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
>  			      struct vmw_fence_obj *fence, u32 seqno,
>  			      void (*destroy) (struct vmw_fence_obj *fence))
>  {
> -	unsigned long irq_flags;
>  	int ret = 0;
>  
>  	fence_init(&fence->base, &vmw_fence_ops, &fman->lock,
> @@ -332,7 +333,7 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
>  	INIT_LIST_HEAD(&fence->seq_passed_actions);
>  	fence->destroy = destroy;
>  
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	if (unlikely(fman->fifo_down)) {
>  		ret = -EBUSY;
>  		goto out_unlock;
> @@ -341,7 +342,7 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
>  	++fman->num_fence_objects;
>  
>  out_unlock:
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  	return ret;
>  
>  }
> @@ -490,11 +491,9 @@ rerun:
>  
>  void vmw_fences_update(struct vmw_fence_manager *fman)
>  {
> -	unsigned long irq_flags;
> -
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	__vmw_fences_update(fman);
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  }
>  
>  bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
> @@ -694,11 +693,9 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
>  
>  void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
>  {
> -	unsigned long irq_flags;
> -
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	fman->fifo_down = false;
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  }
>  
>  
> @@ -825,10 +822,9 @@ void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
>  {
>  	struct vmw_event_fence_action *eaction;
>  	struct drm_pending_event *event;
> -	unsigned long irq_flags;
>  
>  	while (1) {
> -		spin_lock_irqsave(&fman->lock, irq_flags);
> +		spin_lock_bh(&fman->lock);
>  		if (list_empty(event_list))
>  			goto out_unlock;
>  		eaction = list_first_entry(event_list,
> @@ -837,11 +833,11 @@ void vmw_event_fence_fpriv_gone(struct vmw_fence_manager *fman,
>  		list_del_init(&eaction->fpriv_head);
>  		event = eaction->event;
>  		eaction->event = NULL;
> -		spin_unlock_irqrestore(&fman->lock, irq_flags);
> +		spin_unlock_bh(&fman->lock);
>  		event->destroy(event);
>  	}
>  out_unlock:
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  }
>  
>  
> @@ -854,7 +850,7 @@ out_unlock:
>   * This function is called when the seqno of the fence where @action is
>   * attached has passed. It queues the event on the submitter's event list.
>   * This function is always called from atomic context, and may be called
> - * from irq context.
> + * from tasklet context.
>   */
>  static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
>  {
> @@ -863,13 +859,12 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
>  	struct drm_device *dev = eaction->dev;
>  	struct drm_pending_event *event = eaction->event;
>  	struct drm_file *file_priv;
> -	unsigned long irq_flags;
>  
>  	if (unlikely(event == NULL))
>  		return;
>  
>  	file_priv = event->file_priv;
> -	spin_lock_irqsave(&dev->event_lock, irq_flags);
> +	spin_lock_bh(&dev->event_lock);
>  
>  	if (likely(eaction->tv_sec != NULL)) {
>  		struct timeval tv;
> @@ -883,7 +878,7 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
>  	list_add_tail(&eaction->event->link, &file_priv->event_list);
>  	eaction->event = NULL;
>  	wake_up_all(&file_priv->event_wait);
> -	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
> +	spin_unlock_bh(&dev->event_lock);
>  }
>  
>  /**
> @@ -900,11 +895,10 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
>  	struct vmw_event_fence_action *eaction =
>  		container_of(action, struct vmw_event_fence_action, action);
>  	struct vmw_fence_manager *fman = fman_from_fence(eaction->fence);
> -	unsigned long irq_flags;
>  
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	list_del(&eaction->fpriv_head);
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  
>  	vmw_fence_obj_unreference(&eaction->fence);
>  	kfree(eaction);
> @@ -924,11 +918,10 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
>  			      struct vmw_fence_action *action)
>  {
>  	struct vmw_fence_manager *fman = fman_from_fence(fence);
> -	unsigned long irq_flags;
>  	bool run_update = false;
>  
>  	mutex_lock(&fman->goal_irq_mutex);
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  
>  	fman->pending_actions[action->type]++;
>  	if (fence_is_signaled_locked(&fence->base)) {
> @@ -947,7 +940,7 @@ static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
>  		run_update = vmw_fence_goal_check_locked(fence);
>  	}
>  
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  
>  	if (run_update) {
>  		if (!fman->goal_irq_on) {
> @@ -985,7 +978,6 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
>  	struct vmw_event_fence_action *eaction;
>  	struct vmw_fence_manager *fman = fman_from_fence(fence);
>  	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
> -	unsigned long irq_flags;
>  
>  	eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
>  	if (unlikely(eaction == NULL))
> @@ -1002,9 +994,9 @@ int vmw_event_fence_action_queue(struct drm_file *file_priv,
>  	eaction->tv_sec = tv_sec;
>  	eaction->tv_usec = tv_usec;
>  
> -	spin_lock_irqsave(&fman->lock, irq_flags);
> +	spin_lock_bh(&fman->lock);
>  	list_add_tail(&eaction->fpriv_head, &vmw_fp->fence_events);
> -	spin_unlock_irqrestore(&fman->lock, irq_flags);
> +	spin_unlock_bh(&fman->lock);
>  
>  	vmw_fence_obj_add_action(fence, &eaction->action);
>  
> @@ -1025,16 +1017,15 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
>  	struct vmw_event_fence_pending *event;
>  	struct vmw_fence_manager *fman = fman_from_fence(fence);
>  	struct drm_device *dev = fman->dev_priv->dev;
> -	unsigned long irq_flags;
>  	int ret;
>  
> -	spin_lock_irqsave(&dev->event_lock, irq_flags);
> +	spin_lock_bh(&dev->event_lock);
>  
>  	ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
>  	if (likely(ret == 0))
>  		file_priv->event_space -= sizeof(event->event);
>  
> -	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
> +	spin_unlock_bh(&dev->event_lock);
>  
>  	if (unlikely(ret != 0)) {
>  		DRM_ERROR("Failed to allocate event space for this file.\n");
> @@ -1078,9 +1069,9 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
>  out_no_queue:
>  	event->base.destroy(&event->base);
>  out_no_event:
> -	spin_lock_irqsave(&dev->event_lock, irq_flags);
> +	spin_lock_bh(&dev->event_lock);
>  	file_priv->event_space += sizeof(*event);
> -	spin_unlock_irqrestore(&dev->event_lock, irq_flags);
> +	spin_unlock_bh(&dev->event_lock);
>  out_no_space:
>  	return ret;
>  }
> @@ -1172,3 +1163,32 @@ out_no_ref_obj:
>  	vmw_fence_obj_unreference(&fence);
>  	return ret;
>  }
> +
> +/**
> + * vmw_fence_tasklet - Fence manager tasklet entry point
> + *
> + * @data: The tasklet closure - A pointer to the fence manager cast to an
> + * unsigned long.
> + */
> +static void vmw_fence_tasklet(unsigned long data)
> +{
> +	struct vmw_fence_manager *fman = (struct vmw_fence_manager *) data;
> +
> +	spin_lock(&fman->lock);
> +	__vmw_fences_update(fman);
> +	spin_unlock(&fman->lock);
> +	wake_up_all(&fman->dev_priv->fence_queue);
> +}
> +
> +/**
> + * vmw_fence_tasklet_schedule - Schedule a fence manager tasklet run
> + *
> + * @fman: Pointer to a fence manager
> + */
> +void vmw_fence_tasklet_schedule(struct vmw_fence_manager *fman)
> +{
> +	if (!fman)
> +		return;
> +
> +	tasklet_schedule(&fman->tasklet);
> +}
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> index 8be6c29..e55b2c9 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> @@ -124,4 +124,6 @@ extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
>  					uint32_t *tv_sec,
>  					uint32_t *tv_usec,
>  					bool interruptible);
> +extern void vmw_fence_tasklet_schedule(struct vmw_fence_manager *fman);
> +
>  #endif /* _VMWGFX_FENCE_H_ */
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> index ac3eccd..b0a6e65 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> @@ -48,10 +48,8 @@ irqreturn_t vmw_irq_handler(int irq, void *arg)
>  		return IRQ_NONE;
>  
>  	if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
> -			     SVGA_IRQFLAG_FENCE_GOAL)) {
> -		vmw_fences_update(dev_priv->fman);
> -		wake_up_all(&dev_priv->fence_queue);
> -	}
> +			     SVGA_IRQFLAG_FENCE_GOAL))
> +		vmw_fence_tasklet_schedule(dev_priv->fman);
>  
>  	if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS)
>  		wake_up_all(&dev_priv->fifo_queue);
> -- 
> 2.4.3
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet
  2015-10-30 10:23   ` Daniel Vetter
@ 2015-10-30 11:08     ` Thomas Hellstrom
  0 siblings, 0 replies; 6+ messages in thread
From: Thomas Hellstrom @ 2015-10-30 11:08 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

On 10/30/2015 11:23 AM, Daniel Vetter wrote:
> On Fri, Oct 30, 2015 at 02:42:44AM -0700, Thomas Hellstrom wrote:
>> Reduce the time in hardware irq context and hardware irq latency.
>>
>> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
>> Reviewed-by: Sinclair Yeh <syeh@vmware.com>
>> ---
>>  drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 108 ++++++++++++++++++++--------------
>>  drivers/gpu/drm/vmwgfx/vmwgfx_fence.h |   2 +
>>  drivers/gpu/drm/vmwgfx/vmwgfx_irq.c   |   6 +-
>>  3 files changed, 68 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
>> index 8e689b4..f40c36e 100644
>> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
>> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
>> @@ -47,6 +47,7 @@ struct vmw_fence_manager {
>>  	bool seqno_valid; /* Protected by @lock, and may not be set to true
>>  			     without the @goal_irq_mutex held. */
>>  	unsigned ctx;
>> +	struct tasklet_struct tasklet;
> Bottom halves are super-deprecated except for giant existing users like
> networking. I think the recommended way to do this is to either use
> threaded interrupts or work-queues. The reason for that seems to be that
> locking is funky around them, which is a major pain for RT. And RT is
> going mainline now for real.
> -Daniel
>
>

Thanks for the heads up. Unfortunately work-queues introduce too much
latency for this use-case.
Given that we (vmwgfx) already is an existing user (albeit not giant
:)), and RT in a VM guest is somewhat unlikely
I wonder how much of an issue this is.

I'll read up on threaded interrupts.

/Thomas

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-10-30 11:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-30  9:42 [PATCH 1/4] drm/vmwgfx: Replace iowrite/ioread with volatile memory accesses Thomas Hellstrom
2015-10-30  9:42 ` [PATCH 2/4] drm/vmwgfx: Defer fence irq processing to a tasklet Thomas Hellstrom
2015-10-30 10:23   ` Daniel Vetter
2015-10-30 11:08     ` Thomas Hellstrom
2015-10-30  9:42 ` [PATCH 3/4] drm/vmwgfx: Relax irq locking somewhat Thomas Hellstrom
2015-10-30  9:42 ` [PATCH 4/4] drm/vmwgfx: Rework locking around register accesses Thomas Hellstrom

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox