[ddk][mmio] Add mmio-buffer library.
mmio_buffer_t is a helper library to help manage mapping mmios as well
as managing their associated resources.
Tested: It compiles!
Change-Id: I06a51528dbe8a5ee541fedd6988a93af08310e27
diff --git a/system/ulib/ddk/include/ddk/mmio-buffer.h b/system/ulib/ddk/include/ddk/mmio-buffer.h
new file mode 100644
index 0000000..1b12c4b
--- /dev/null
+++ b/system/ulib/ddk/include/ddk/mmio-buffer.h
@@ -0,0 +1,43 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/types.h>
+
+__BEGIN_CDECLS;
+
+typedef struct {
+ // |vaddr| points to the content starting at |offset| in |vmo|.
+ void* vaddr;
+ zx_off_t offset;
+ size_t size;
+ zx_handle_t vmo;
+} mmio_buffer_t;
+
+typedef struct {
+ const mmio_buffer_t* mmio;
+ zx_handle_t pmt;
+ // |paddr| points to the content starting at |mmio->offset| in |mmio->vmo|.
+ zx_paddr_t paddr;
+} mmio_pinned_buffer_t;
+
+// Takes raw mmio resources, and maps it into address space. |offset| is the
+// offset from the begining of |vmo| where the mmio region begins. |size|
+// specifies the size of the mmio region. |offset| + |size| must be less than
+// or equal to the size of |vmo|.
+// Always consumes |vmo|, including in error cases.
+zx_status_t mmio_buffer_init(mmio_buffer_t* buffer, zx_off_t offset, size_t size,
+ zx_handle_t vmo, uint32_t cache_policy);
+// Unmaps the mmio region.
+void mmio_buffer_release(mmio_buffer_t* buffer);
+
+// Returns a pinned buffer if successful. |buffer| must outlive |out|.
+//
+// Example usage: A device needs access to another device's MMIO space.
+zx_status_t mmio_buffer_pin(mmio_buffer_t* buffer, zx_handle_t bti, mmio_pinned_buffer_t* out);
+// Unpins the buffer.
+void mmio_buffer_unpin(mmio_pinned_buffer_t* buffer);
+
+__END_CDECLS;
diff --git a/system/ulib/ddk/mmio-buffer.c b/system/ulib/ddk/mmio-buffer.c
new file mode 100644
index 0000000..47014cd
--- /dev/null
+++ b/system/ulib/ddk/mmio-buffer.c
@@ -0,0 +1,77 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddk/mmio-buffer.h>
+
+#include <string.h>
+
+#include <ddk/driver.h>
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#include <zircon/types.h>
+
+zx_status_t mmio_buffer_init(mmio_buffer_t* buffer, zx_off_t offset, size_t size,
+ zx_handle_t vmo, uint32_t cache_policy) {
+ zx_status_t status = zx_vmo_set_cache_policy(vmo, cache_policy);
+ if (status != ZX_OK) {
+ zx_handle_close(vmo);
+ return status;
+ }
+
+ uintptr_t vaddr;
+ const size_t vmo_offset = ROUNDDOWN(offset, ZX_PAGE_SIZE);
+ const size_t page_offset = offset - vmo_offset;
+ const size_t vmo_size = ROUNDUP(size + page_offset, ZX_PAGE_SIZE);
+
+ status = zx_vmar_map(zx_vmar_root_self(),
+ ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE,
+ 0, vmo, vmo_offset, vmo_size, &vaddr);
+ if (status != ZX_OK) {
+ zx_handle_close(vmo);
+ return status;
+ }
+
+ buffer->vmo = vmo;
+ buffer->vaddr = (void*)(vaddr + page_offset);
+ buffer->offset = offset;
+ buffer->size = size;
+
+ return ZX_OK;
+}
+
+void mmio_buffer_release(mmio_buffer_t* buffer) {
+ if (buffer->vmo != ZX_HANDLE_INVALID) {
+ zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)buffer->vaddr, buffer->size);
+ zx_handle_close(buffer->vmo);
+ buffer->vmo = ZX_HANDLE_INVALID;
+ }
+}
+
+zx_status_t mmio_buffer_pin(mmio_buffer_t* buffer, zx_handle_t bti, mmio_pinned_buffer_t* out) {
+ zx_paddr_t paddr;
+ zx_handle_t pmt;
+ const uint32_t options = ZX_BTI_PERM_WRITE | ZX_BTI_PERM_READ;
+ const size_t vmo_offset = ROUNDDOWN(buffer->offset, ZX_PAGE_SIZE);
+ const size_t page_offset = buffer->offset - vmo_offset;
+ const size_t vmo_size = ROUNDUP(buffer->size + page_offset, ZX_PAGE_SIZE);
+
+ zx_status_t status = zx_bti_pin(bti, options, buffer->vmo, vmo_offset, vmo_size,
+ &paddr, 1, &pmt);
+ if (status != ZX_OK) {
+ return status;
+ }
+
+ out->mmio = buffer;
+ out->paddr = paddr + page_offset;
+ out->pmt = pmt;
+
+ return ZX_OK;
+}
+
+void mmio_buffer_unpin(mmio_pinned_buffer_t* buffer) {
+ if (buffer->pmt != ZX_HANDLE_INVALID) {
+ zx_pmt_unpin(buffer->pmt);
+ buffer->pmt = ZX_HANDLE_INVALID;
+ }
+}
diff --git a/system/ulib/ddk/rules.mk b/system/ulib/ddk/rules.mk
index f1a9509..baa6136 100644
--- a/system/ulib/ddk/rules.mk
+++ b/system/ulib/ddk/rules.mk
@@ -12,6 +12,7 @@
MODULE_SRCS += \
$(LOCAL_DIR)/io-buffer.c \
+ $(LOCAL_DIR)/mmio-buffer.c \
$(LOCAL_DIR)/phys-iter.c \
MODULE_STATIC_LIBS := system/ulib/pretty system/ulib/sync