msm:ocmem: ocmem_drop api

The drop api is similar to the ocmem_unmap api but does not do
any of the actual transfers from the OCMEM to the DDR, this is
needed during audio subsystem restart.

Change-Id: If78744da8aede0f7f4e5da38feb9ce720201ac90
Signed-off-by: Neeti Desai <neetid@codeaurora.org>
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 906bd4a..868fd1a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -532,6 +532,9 @@
 	struct ocmem_req *matched_req = NULL;
 	struct ocmem_region *matched_region = NULL;
 
+	if (!TEST_STATE(req, R_MAPPED))
+		goto invalid_op_error;
+
 	matched_region = find_region_match(req->req_start, req->req_end);
 	matched_req = find_req_match(req->req_id, matched_region);
 
@@ -1501,22 +1504,25 @@
 		mutex_unlock(&sched_mutex);
 	}
 
-	if (TEST_STATE(req, R_MAPPED)) {
-		/* unmap the interval and clear the memory */
-		rc = process_unmap(req, req->req_start, req->req_end);
+	if (!TEST_STATE(req, R_FREE)) {
 
-		if (rc < 0) {
-			pr_err("ocmem: Failed to unmap %p\n", req);
-			goto free_fail;
-		}
+		if (TEST_STATE(req, R_MAPPED)) {
+			/* unmap the interval and clear the memory */
+			rc = process_unmap(req, req->req_start, req->req_end);
 
-		rc = do_free(req);
-		if (rc < 0) {
-			pr_err("ocmem: Failed to free %p\n", req);
-			goto free_fail;
-		}
-	} else
+			if (rc < 0) {
+				pr_err("ocmem: Failed to unmap %p\n", req);
+				goto free_fail;
+			}
+
+			rc = do_free(req);
+			if (rc < 0) {
+				pr_err("ocmem: Failed to free %p\n", req);
+				goto free_fail;
+			}
+		} else
 			pr_debug("request %p was already shrunk to 0\n", req);
+	}
 
 	/* Turn off the memory */
 	if (req->req_sz != 0) {
@@ -1603,6 +1609,42 @@
 	return 0;
 }
 
+int process_drop(int id, struct ocmem_handle *handle,
+				 struct ocmem_map_list *list)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request drop\n", id);
+		return -EINVAL;
+	}
+
+	if (is_tcm(id))
+		pr_err("Client %d cannot request drop\n", id);
+
+	req = handle_to_req(handle);
+	buffer = handle_to_buffer(handle);
+
+	if (!req)
+		return -EINVAL;
+
+	if (req->req_start != core_address(id, buffer->addr)) {
+		pr_err("Invalid buffer handle passed for drop\n");
+		return -EINVAL;
+	}
+
+	if (TEST_STATE(req, R_MAPPED)) {
+		rc = process_unmap(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
 int process_xfer_out(int id, struct ocmem_handle *handle,
 			struct ocmem_map_list *list)
 {