Add reference counting to omap_bo

Add reference counting to omap_bo to avoid freeing a buffer object
during page flip.

BUG=chrome-os-partner:12889
TEST=Tested on snow, could hotplug & resize while flipping

Change-Id: I7b65e9553427ce1668d2838712e1e18e47a80f79
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31771
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 956c3ac..da1f2f1 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1054,7 +1054,7 @@
 	      || (pScrn->bitsPerPixel != omap_bo_bpp(pOMAP->scanout)) ) {
 
 		/* delete old scanout buffer */
-		omap_bo_del(pOMAP->scanout);
+		omap_bo_unreference(pOMAP->scanout);
 		pOMAP->has_resized = TRUE;
 		DEBUG_MSG("allocating new scanout buffer: %dx%d",
 				width, height);
diff --git a/src/omap_dri2.c b/src/omap_dri2.c
index 2645aef..8e0f39f 100644
--- a/src/omap_dri2.c
+++ b/src/omap_dri2.c
@@ -362,11 +362,18 @@
 	OMAPPtr pOMAP = OMAPPTR(pScrn);
 	DrawablePtr pDraw = NULL;
 	int status;
-	OMAPPixmapPrivPtr dst_priv;
+	OMAPPixmapPrivPtr src_priv, dst_priv;
+	struct omap_bo *old_src_bo, *old_dst_bo;
 
 	if (--cmd->swapCount > 0)
 		return;
 
+	/* Save the old source bo for unreference below */
+	src_priv = exaGetPixmapDriverPrivate(OMAPBUF(cmd->pSrcBuffer)->pPixmap);
+	dst_priv = exaGetPixmapDriverPrivate(OMAPBUF(cmd->pDstBuffer)->pPixmap);
+	old_src_bo = src_priv->bo;
+	old_dst_bo = dst_priv->bo;
+
 	if ((cmd->flags & OMAP_SWAP_FAIL) == 0) {
 		DEBUG_MSG("%s complete: %d -> %d", swap_names[cmd->type],
 				cmd->pSrcBuffer->attachment, cmd->pDstBuffer->attachment);
@@ -395,6 +402,8 @@
 	 */
 	OMAPDRI2DestroyBuffer(pDraw, cmd->pSrcBuffer);
 	OMAPDRI2DestroyBuffer(pDraw, cmd->pDstBuffer);
+	omap_bo_unreference(old_src_bo);
+	omap_bo_unreference(old_dst_bo);
 	pOMAP->pending_flips--;
 
 	free(cmd);
@@ -476,6 +485,8 @@
 	src->previous_canflip = new_canflip;
 	dst->previous_canflip = new_canflip;
 
+	omap_bo_reference(src_priv->bo);
+	omap_bo_reference(dst_priv->bo);
 	if (src_fb_id && dst_fb_id && canflip(pDraw) && !(pOMAP->has_resized)) {
 		/* has_resized: On hotplug the fb size and crtc sizes arent updated
 		* hence on this event we do a copyb but flip from the next frame
diff --git a/src/omap_drmif_fb.h b/src/omap_drmif_fb.h
index b1be641..26aa8a2 100644
--- a/src/omap_drmif_fb.h
+++ b/src/omap_drmif_fb.h
@@ -47,6 +47,8 @@
 uint32_t omap_bo_pitch(struct omap_bo *bo);
 void *omap_bo_addr(struct omap_bo *bo);
 int omap_bo_clear(struct omap_bo *bo);
+void omap_bo_reference(struct omap_bo *bo);
+void omap_bo_unreference(struct omap_bo *bo);
 
 #endif /* OMAP_DRMIF_FB_H_ */
 
diff --git a/src/omap_dumb.c b/src/omap_dumb.c
index 070d463..9afe87a 100644
--- a/src/omap_dumb.c
+++ b/src/omap_dumb.c
@@ -47,6 +47,7 @@
 	uint8_t depth;
 	uint8_t bpp;
 	uint32_t pitch;
+	int refcnt;
 };
 
 /* device related functions:
@@ -108,6 +109,7 @@
 	new_buf->height = create_dumb.height;
 	new_buf->depth = depth;
 	new_buf->bpp = create_dumb.bpp;
+	new_buf->refcnt = 1;
 
 	return new_buf;
 }
@@ -138,6 +140,22 @@
 	free(bo);
 }
 
+void omap_bo_unreference(struct omap_bo *bo)
+{
+	if (!bo)
+		return;
+
+	assert(bo->refcnt > 0);
+	if (--bo->refcnt == 0)
+		omap_bo_del(bo);
+}
+
+void omap_bo_reference(struct omap_bo *bo)
+{
+	assert(bo->refcnt > 0);
+	bo->refcnt++;
+}
+
 int omap_bo_get_name(struct omap_bo *bo, uint32_t *name)
 {
 	int ret;
diff --git a/src/omap_exa.c b/src/omap_exa.c
index 2552835..cf2e294 100644
--- a/src/omap_exa.c
+++ b/src/omap_exa.c
@@ -76,7 +76,7 @@
 {
 	OMAPPixmapPrivPtr priv = driverPriv;
 
-	omap_bo_del(priv->bo);
+	omap_bo_unreference(priv->bo);
 
 	free(priv);
 }
@@ -105,7 +105,7 @@
 		/* scratch-pixmap (see GetScratchPixmapHeader()) gets recycled,
 		 * so could have a previous bo!
 		 */
-		omap_bo_del(priv->bo);
+		omap_bo_unreference(priv->bo);
 		priv->bo = NULL;
 
 		/* Returning FALSE calls miModifyPixmapHeader */
@@ -144,7 +144,7 @@
 	    omap_bo_height(priv->bo) != pPixmap->drawable.height ||
 	    omap_bo_bpp(priv->bo) != pPixmap->drawable.bitsPerPixel) {
 		/* re-allocate buffer! */
-		omap_bo_del(priv->bo);
+		omap_bo_unreference(priv->bo);
 		priv->bo = omap_bo_new_with_dim(pOMAP->dev,
 				pPixmap->drawable.width,
 				pPixmap->drawable.height,