Keep payload buffer mapped for its lifetime

This saves the cost of mapping it for every bridge command.

Change-Id: Ib536022a0cdc275339331d20b9a8615275d5c76b
diff --git a/fuchsia/msd_img_buffer.h b/fuchsia/msd_img_buffer.h
index fef1dab..b5c66ec 100644
--- a/fuchsia/msd_img_buffer.h
+++ b/fuchsia/msd_img_buffer.h
@@ -23,10 +23,25 @@
 		return platform_buf_.get();
 	}
 
+	bool GetPersistentCpuMap(void** data_out)
+	{
+		if (!data_)
+		{
+			if (!platform_buf_->MapCpu(&data_))
+			{
+				return DRETF(false, "Failed to map persistent");
+			}
+		}
+
+		*data_out = data_;
+		return true;
+	}
+
 private:
 	MsdImgBuffer(std::unique_ptr<magma::PlatformBuffer> platform_buf);
 
 	std::unique_ptr<magma::PlatformBuffer> platform_buf_;
+	void* data_ = nullptr;
 };
 
 class MsdImgAbiBuffer : public msd_buffer_t
diff --git a/fuchsia/msd_img_connection.cc b/fuchsia/msd_img_connection.cc
index f7de970..4869dfc 100644
--- a/fuchsia/msd_img_connection.cc
+++ b/fuchsia/msd_img_connection.cc
@@ -108,8 +108,10 @@
 		return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Payload buffer too small for struct");
 	}
 	void *data;
-	if (!payload_buffer->platform_buffer()->MapCpu(&data))
-		return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "Can't map paload buffer");
+	if (!payload_buffer->GetPersistentCpuMap(&data))
+	{
+		return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "Unable to make persistent map");
+	}
 
 	payload = reinterpret_cast<volatile FuchsiaImgCommandPayload *>(data);
 
@@ -123,12 +125,10 @@
 
 	if (remaining_buffer_size < package_out->ui32InBufferSize)
 	{
-		payload_buffer->platform_buffer()->UnmapCpu();
 		return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Payload buffer too small for in args");
 	}
 	if (remaining_buffer_size < package_out->ui32OutBufferSize)
 	{
-		payload_buffer->platform_buffer()->UnmapCpu();
 		return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Payload buffer too small for out args");
 	}
 	// Volatile isn't necessary because the bridge code will memcpy everything
@@ -155,7 +155,7 @@
 
 	ScopedSetConnection set_connection(this);
 	PVRSRV_ERROR eError = BridgedDispatchKM(connection_data_, &package);
-	payload_buffer_->platform_buffer()->UnmapCpu();
+	payload_buffer_ = nullptr;
 	additional_buffer_.reset();
 	current_client_thread_id_ = 0;
 	if (eError != PVRSRV_OK)
diff --git a/test/test_msd_img_connection.cc b/test/test_msd_img_connection.cc
index 99da492..0fef6a2 100644
--- a/test/test_msd_img_connection.cc
+++ b/test/test_msd_img_connection.cc
@@ -80,12 +80,20 @@
 		EXPECT_EQ(payload_buf.base_ptr(), connection.payload_buffer_);
 		EXPECT_EQ(nullptr, connection.TakeAdditionalBuffer());
 
+		// Unmap to test whether the buffer was mapped persistently.
+		ASSERT_TRUE(payload_buf.base_ptr()->platform_buffer()->UnmapCpu());
+		connection.payload_buffer_ = nullptr;
+
 		// 2 resources are given, so the last should be used as the
 		// additional buffer.
 		system_buf->num_resources = 2;
 		EXPECT_EQ(MAGMA_STATUS_OK, connection.ProcessCommandBuffer(&cmd_buf, exec_resources, &package));
 		EXPECT_EQ(additional_buf.base_ptr(), connection.TakeAdditionalBuffer());
 		EXPECT_EQ(nullptr, connection.TakeAdditionalBuffer());
+
+		// The parameters should be at the same address because the
+		// buffer has a persistent mapping.
+		EXPECT_EQ(payload_buf_data + 1, package.pvParamIn);
 	}
 };