gma500: GEM - now we have the basics we shall stick pins in it

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/gma500/psb_gtt.c b/drivers/staging/gma500/psb_gtt.c
index 090d30e..a991c12 100644
--- a/drivers/staging/gma500/psb_gtt.c
+++ b/drivers/staging/gma500/psb_gtt.c
@@ -66,7 +66,6 @@
 	return dev_priv->gtt_map + (offset >> PAGE_SHIFT);
 }
 
-
 /**
  *	psb_gtt_insert	-	put an object into the GART
  *	@dev: our DRM device
@@ -77,21 +76,19 @@
  *
  *	FIXME: gtt lock ?
  */
-int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
+static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
 {
 	u32 *gtt_slot, pte;
 	int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT;
 	struct page **pages;
 	int i;
 
-	if (r->stolen)
-		return 0;
 	if (r->pages == NULL) {
 		WARN_ON(1);
 		return -EINVAL;
 	}
 
-	WARN_ON(r->in_gart);	/* refcount these maybe ? */
+	WARN_ON(r->stolen);	/* refcount these maybe ? */
 
 	gtt_slot = psb_gtt_entry(dev, r);
 	pages = r->pages;
@@ -118,16 +115,14 @@
  *	page table entries with the dummy page
  */
 
-void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
+static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	u32 *gtt_slot, pte;
 	int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT;
 	int i;
 
-	if (r->stolen)
-		return;
-	WARN_ON(!r->in_gart);
+	WARN_ON(r->stolen);
 
 	gtt_slot = psb_gtt_entry(dev, r);
 	pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0);;
@@ -146,7 +141,7 @@
  *	Pin and build an in kernel list of the pages that back our GEM object.
  *	While we hold this the pages cannot be swapped out
  */
-int psb_gtt_attach_pages(struct gtt_range *gt)
+static int psb_gtt_attach_pages(struct gtt_range *gt)
 {
 	struct inode *inode;
 	struct address_space *mapping;
@@ -189,13 +184,11 @@
  *	must have been removed from the GART as they could now be paged out
  *	and move bus address.
  */
-void psb_gtt_detach_pages(struct gtt_range *gt)
+static void psb_gtt_detach_pages(struct gtt_range *gt)
 {
 	int i;
 	int pages = (gt->resource.end + 1 - gt->resource.start) >> PAGE_SHIFT;
 
-	WARN_ON(gt->in_gart);
-
 	for (i = 0; i < pages; i++) {
 		/* FIXME: do we need to force dirty */
 		set_page_dirty(gt->pages[i]);
@@ -207,6 +200,50 @@
 }
 
 /*
+ *	Manage pinning of resources into the GART
+ */
+
+int psb_gtt_pin(struct drm_device *dev, struct gtt_range *gt)
+{
+	int ret;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev_priv->gtt_mutex);
+
+	if (gt->in_gart == 0 && gt->stolen == 0) {
+		ret = psb_gtt_attach_pages(gt);
+		if (ret < 0)
+			goto out;
+		ret = psb_gtt_insert(dev, gt);
+		if (ret < 0) {
+			psb_gtt_detach_pages(gt);
+			goto out;
+		}
+	}
+	gt->in_gart++;
+out:
+	mutex_unlock(&dev_priv->gtt_mutex);
+	return ret;
+}
+
+void psb_gtt_unpin(struct drm_device *dev, struct gtt_range *gt)
+{
+	struct drm_psb_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev_priv->gtt_mutex);
+
+	WARN_ON(!gt->in_gart);
+
+	gt->in_gart--;
+	if (gt->in_gart == 0 && gt->stolen == 0) {
+		psb_gtt_remove(dev, gt);
+		psb_gtt_detach_pages(gt);
+	}
+
+	mutex_unlock(&dev_priv->gtt_mutex);
+}
+	
+/*
  *	GTT resource allocator - allocate and manage GTT address space
  */
 
@@ -265,10 +302,7 @@
 static void psb_gtt_destroy(struct kref *kref)
 {
 	struct gtt_range *gt = container_of(kref, struct gtt_range, kref);
-	if (gt->in_gart && !gt->stolen)
-		psb_gtt_remove(gt->gem.dev, gt);
-	if (gt->pages)
-		psb_gtt_detach_pages(gt);
+	WARN_ON(gt->in_gart && !gt->stolen);
 	release_resource(&gt->resource);
 	kfree(gt);
 }
@@ -345,6 +379,8 @@
 	int ret = 0;
 	uint32_t pte;
 
+	mutex_init(&dev_priv->gtt_mutex);
+
 	dev_priv->pg = pg = psb_gtt_alloc(dev);
 	if (pg == NULL)
 	        return -ENOMEM;
diff --git a/drivers/staging/gma500/psb_gtt.h b/drivers/staging/gma500/psb_gtt.h
index b5d6530..dc553e0 100644
--- a/drivers/staging/gma500/psb_gtt.h
+++ b/drivers/staging/gma500/psb_gtt.h
@@ -44,18 +44,17 @@
 	struct resource resource;
 	u32 offset;
 	struct kref kref;
-        struct drm_gem_object gem;	/* GEM high level stuff */
-        int in_gart;			/* Currently in the GART */
-        int stolen;			/* Backed from stolen RAM */
-        struct page **pages;		/* Backing pages if present */
+	struct drm_gem_object gem;	/* GEM high level stuff */
+	int in_gart;			/* Currently in the GART (ref ct) */
+        bool stolen;			/* Backed from stolen RAM */
+	struct page **pages;		/* Backing pages if present */
 };
 
-extern int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r);
-extern void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r);
-
 extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
 						const char *name, int backed);
 extern void psb_gtt_kref_put(struct gtt_range *gt);
 extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt);
+extern int psb_gtt_pin(struct drm_device *dev, struct gtt_range *gt);
+extern void psb_gtt_unpin(struct drm_device *dev, struct gtt_range *gt);
 
 #endif
diff --git a/drivers/staging/gma500/psb_intel_display.c b/drivers/staging/gma500/psb_intel_display.c
index 4d384d5..b5a36d2 100644
--- a/drivers/staging/gma500/psb_intel_display.c
+++ b/drivers/staging/gma500/psb_intel_display.c
@@ -341,7 +341,6 @@
 	/* struct drm_i915_master_private *master_priv; */
 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
 	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
-	struct psb_intel_mode_device *mode_dev = psb_intel_crtc->mode_dev;
 	int pipe = psb_intel_crtc->pipe;
 	unsigned long start, offset;
 	int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
@@ -1020,8 +1019,6 @@
 				 uint32_t width, uint32_t height)
 {
 	struct drm_device *dev = crtc->dev;
-	struct drm_psb_private *dev_priv =
-				(struct drm_psb_private *)dev->dev_private;
 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
 	int pipe = psb_intel_crtc->pipe;
 	uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
@@ -1048,6 +1045,9 @@
 
 		/* Unpin the old GEM object */
 		if (psb_intel_crtc->cursor_obj) {
+                	gt = container_of(psb_intel_crtc->cursor_obj,
+                	                        struct gtt_range, gem);
+			psb_gtt_unpin(crtc->dev, gt);
 			drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
 			psb_intel_crtc->cursor_obj = NULL;
 		}
@@ -1070,19 +1070,17 @@
 		return -ENOMEM;
 	}
 
-	/*insert this bo into gtt*/
-	DRM_DEBUG("%s: map meminfo for hw cursor. handle %x\n",
-						__func__, handle);
-
-/* Pin : FIXME
-	if (ret) {
-		DRM_ERROR("Can not map meminfo to GTT. handle 0x%x\n", handle);
-		return ret;
-	}
-*/
 	gt = container_of(obj, struct gtt_range, gem);
 
-	addr = gt->resource.start;
+	/* Pin the memory into the GTT */
+	ret = psb_gtt_pin(crtc->dev, gt);
+	if (ret) {
+		DRM_ERROR("Can not pin down handle 0x%x\n", handle);
+		return ret;
+	}
+
+
+	addr = gt->offset;	/* Or resource.start ??? */
 
 	psb_intel_crtc->cursor_addr = addr;
 
@@ -1099,6 +1097,9 @@
 
 	/* unpin the old bo */
 	if (psb_intel_crtc->cursor_obj && psb_intel_crtc->cursor_obj != obj) {
+               	gt = container_of(psb_intel_crtc->cursor_obj,
+               	                        struct gtt_range, gem);
+		psb_gtt_unpin(crtc->dev, gt);
 		drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
 		psb_intel_crtc->cursor_obj = obj;
 	}
@@ -1301,8 +1302,16 @@
 static void psb_intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+	struct gtt_range *gt;
 
-	/* FIXME: do we need to put the final GEM cursor ? */
+	/* Unpin the old GEM object */
+	if (psb_intel_crtc->cursor_obj) {
+		gt = container_of(psb_intel_crtc->cursor_obj,
+						struct gtt_range, gem);
+		psb_gtt_unpin(crtc->dev, gt);
+		drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
+		psb_intel_crtc->cursor_obj = NULL;
+	}
 	kfree(psb_intel_crtc->crtc_state);
 	drm_crtc_cleanup(crtc);
 	kfree(psb_intel_crtc);