* [PATCH v12 RESEND 2/4] tee: generic TEE subsystem
From: Jens Wiklander @ 2016-10-28 10:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477649984-16777-1-git-send-email-jens.wiklander@linaro.org>
Initial patch for generic TEE subsystem.
This subsystem provides:
* Registration/un-registration of TEE drivers.
* Shared memory between normal world and secure world.
* Ioctl interface for interaction with user space.
* Sysfs implementation_id of TEE driver
A TEE (Trusted Execution Environment) driver is a driver that interfaces
with a trusted OS running in some secure environment, for example,
TrustZone on ARM cpus, or a separate secure co-processor etc.
The TEE subsystem can serve a TEE driver for a Global Platform compliant
TEE, but it's not limited to only Global Platform TEEs.
This patch builds on other similar implementations trying to solve
the same problem:
* "optee_linuxdriver" by among others
Jean-michel DELORME<jean-michel.delorme@st.com> and
Emmanuel MICHEL <emmanuel.michel@st.com>
* "Generic TrustZone Driver" by Javier Gonz?lez <javier@javigon.com>
Reviewed-by: Javier Gonz?lez <javier@javigon.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
---
Documentation/ioctl/ioctl-number.txt | 1 +
MAINTAINERS | 7 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/tee/Kconfig | 8 +
drivers/tee/Makefile | 4 +
drivers/tee/tee_core.c | 901 +++++++++++++++++++++++++++++++++++
drivers/tee/tee_private.h | 129 +++++
drivers/tee/tee_shm.c | 357 ++++++++++++++
drivers/tee/tee_shm_pool.c | 158 ++++++
include/linux/tee_drv.h | 278 +++++++++++
include/uapi/linux/tee.h | 403 ++++++++++++++++
12 files changed, 2249 insertions(+)
create mode 100644 drivers/tee/Kconfig
create mode 100644 drivers/tee/Makefile
create mode 100644 drivers/tee/tee_core.c
create mode 100644 drivers/tee/tee_private.h
create mode 100644 drivers/tee/tee_shm.c
create mode 100644 drivers/tee/tee_shm_pool.c
create mode 100644 include/linux/tee_drv.h
create mode 100644 include/uapi/linux/tee.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 81c7f2b..efb38da 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -308,6 +308,7 @@ Code Seq#(hex) Include File Comments
0xA3 80-8F Port ACL in development:
<mailto:tlewis@mindspring.com>
0xA3 90-9F linux/dtlk.h
+0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
0xAA 00-3F linux/uapi/linux/userfaultfd.h
0xAB 00-1F linux/nbd.h
0xAC 00-1F linux/raw.h
diff --git a/MAINTAINERS b/MAINTAINERS
index c447953..de9cd07 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10634,6 +10634,13 @@ F: drivers/hwtracing/stm/
F: include/linux/stm.h
F: include/uapi/linux/stm.h
+TEE SUBSYSTEM
+M: Jens Wiklander <jens.wiklander@linaro.org>
+S: Maintained
+F: include/linux/tee_drv.h
+F: include/uapi/linux/tee.h
+F: drivers/tee/
+
THUNDERBOLT DRIVER
M: Andreas Noever <andreas.noever@gmail.com>
S: Maintained
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e1e2066..de581c1 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -202,4 +202,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/tee/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 194d20b..4d53367 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -173,3 +173,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
+obj-$(CONFIG_TEE) += tee/
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
new file mode 100644
index 0000000..50c244e
--- /dev/null
+++ b/drivers/tee/Kconfig
@@ -0,0 +1,8 @@
+# Generic Trusted Execution Environment Configuration
+config TEE
+ tristate "Trusted Execution Environment support"
+ select DMA_SHARED_BUFFER
+ select GENERIC_ALLOCATOR
+ help
+ This implements a generic interface towards a Trusted Execution
+ Environment (TEE).
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
new file mode 100644
index 0000000..ec64047
--- /dev/null
+++ b/drivers/tee/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_TEE) += tee.o
+tee-objs += tee_core.o
+tee-objs += tee_shm.o
+tee-objs += tee_shm_pool.o
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
new file mode 100644
index 0000000..2045210
--- /dev/null
+++ b/drivers/tee/tee_core.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uaccess.h>
+#include "tee_private.h"
+
+#define TEE_NUM_DEVICES 32
+
+#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
+
+/*
+ * Unprivileged devices in the lower half range and privileged devices in
+ * the upper half range.
+ */
+static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES);
+static DEFINE_SPINLOCK(driver_lock);
+
+static struct class *tee_class;
+static dev_t tee_devt;
+
+static int tee_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+ struct tee_device *teedev;
+ struct tee_context *ctx;
+
+ teedev = container_of(inode->i_cdev, struct tee_device, cdev);
+ if (!tee_device_get(teedev))
+ return -EINVAL;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ ctx->teedev = teedev;
+ INIT_LIST_HEAD(&ctx->list_shm);
+ filp->private_data = ctx;
+ rc = teedev->desc->ops->open(ctx);
+ if (rc)
+ goto err;
+
+ return 0;
+err:
+ kfree(ctx);
+ tee_device_put(teedev);
+ return rc;
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+ struct tee_context *ctx = filp->private_data;
+ struct tee_device *teedev = ctx->teedev;
+ struct tee_shm *shm;
+
+ ctx->teedev->desc->ops->release(ctx);
+ mutex_lock(&ctx->teedev->mutex);
+ list_for_each_entry(shm, &ctx->list_shm, link)
+ shm->ctx = NULL;
+ mutex_unlock(&ctx->teedev->mutex);
+ kfree(ctx);
+ tee_device_put(teedev);
+ return 0;
+}
+
+static int tee_ioctl_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data __user *uvers)
+{
+ struct tee_ioctl_version_data vers;
+
+ ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);
+ if (copy_to_user(uvers, &vers, sizeof(vers)))
+ return -EFAULT;
+ return 0;
+}
+
+static int tee_ioctl_shm_alloc(struct tee_context *ctx,
+ struct tee_ioctl_shm_alloc_data __user *udata)
+{
+ long ret;
+ struct tee_ioctl_shm_alloc_data data;
+ struct tee_shm *shm;
+
+ if (copy_from_user(&data, udata, sizeof(data)))
+ return -EFAULT;
+
+ /* Currently no input flags are supported */
+ if (data.flags)
+ return -EINVAL;
+
+ data.id = -1;
+
+ shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ data.id = shm->id;
+ data.flags = shm->flags;
+ data.size = shm->size;
+
+ if (copy_to_user(udata, &data, sizeof(data)))
+ ret = -EFAULT;
+ else
+ ret = tee_shm_get_fd(shm);
+
+ /*
+ * When user space closes the file descriptor the shared memory
+ * should be freed or if tee_shm_get_fd() failed then it will
+ * be freed immediately.
+ */
+ tee_shm_put(shm);
+ return ret;
+}
+
+static int params_from_user(struct tee_context *ctx, struct tee_param *params,
+ size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_shm *shm;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK)
+ return -EINVAL;
+
+ params[n].attr = ip.attr;
+ switch (ip.attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ params[n].u.value.a = ip.u.value.a;
+ params[n].u.value.b = ip.u.value.b;
+ params[n].u.value.c = ip.u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * If we fail to get a pointer to a shared memory
+ * object (and increase the ref count) from an
+ * identifier we return an error. All pointers that
+ * has been added in params have an increased ref
+ * count. It's the callers responibility to do
+ * tee_shm_put() on all resolved pointers.
+ */
+ shm = tee_shm_get_from_id(ctx, ip.u.memref.shm_id);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ params[n].u.memref.shm_offs = ip.u.memref.shm_offs;
+ params[n].u.memref.size = ip.u.memref.size;
+ params[n].u.memref.shm = shm;
+ break;
+ default:
+ /* Unknown attribute */
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int params_to_user(struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param __user *up = uparams + n;
+ struct tee_param *p = params + n;
+
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ if (put_user(p->u.value.a, &up->u.value.a) ||
+ put_user(p->u.value.b, &up->u.value.b) ||
+ put_user(p->u.value.c, &up->u.value.c))
+ return -EFAULT;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ if (put_user((u64)p->u.memref.size, &up->u.memref.size))
+ return -EFAULT;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static bool param_is_memref(struct tee_param *param)
+{
+ switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int tee_ioctl_open_session(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_open_session_arg __user *uarg;
+ struct tee_ioctl_open_session_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+ bool have_session = false;
+
+ if (!ctx->teedev->desc->ops->open_session)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
+ return -EINVAL;
+
+ uarg = (struct tee_ioctl_open_session_arg __user *)(unsigned long)
+ buf.buf_ptr;
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = (struct tee_ioctl_param __user *)(uarg + 1);
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
+ if (rc)
+ goto out;
+ have_session = true;
+
+ if (put_user(arg.session, &uarg->session) ||
+ put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ /*
+ * If we've succeeded to open the session but failed to communicate
+ * it back to user space, close the session again to avoid leakage.
+ */
+ if (rc && have_session && ctx->teedev->desc->ops->close_session)
+ ctx->teedev->desc->ops->close_session(ctx, arg.session);
+
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+
+ return rc;
+}
+
+static int tee_ioctl_invoke(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_invoke_arg __user *uarg;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+
+ if (!ctx->teedev->desc->ops->invoke_func)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_invoke_arg))
+ return -EINVAL;
+
+ uarg = (struct tee_ioctl_invoke_arg __user *)(unsigned long)buf.buf_ptr;
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = (struct tee_ioctl_param __user *)(uarg + 1);
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params);
+ if (rc)
+ goto out;
+
+ if (put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+ return rc;
+}
+
+static int tee_ioctl_cancel(struct tee_context *ctx,
+ struct tee_ioctl_cancel_arg __user *uarg)
+{
+ struct tee_ioctl_cancel_arg arg;
+
+ if (!ctx->teedev->desc->ops->cancel_req)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id,
+ arg.session);
+}
+
+static int
+tee_ioctl_close_session(struct tee_context *ctx,
+ struct tee_ioctl_close_session_arg __user *uarg)
+{
+ struct tee_ioctl_close_session_arg arg;
+
+ if (!ctx->teedev->desc->ops->close_session)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->close_session(ctx, arg.session);
+}
+
+static int params_to_supp(struct tee_context *ctx,
+ struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param ip;
+ struct tee_param *p = params + n;
+
+ ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK;
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ ip.u.value.a = p->u.value.a;
+ ip.u.value.b = p->u.value.b;
+ ip.u.value.c = p->u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ ip.u.memref.size = p->u.memref.size;
+ if (!p->u.memref.shm) {
+ ip.u.memref.shm_offs = 0;
+ ip.u.memref.shm_id = -1;
+ break;
+ }
+ ip.u.memref.shm_offs = p->u.memref.shm_offs;
+ ip.u.memref.shm_id = p->u.memref.shm->id;
+ break;
+ default:
+ memset(&ip.u, 0, sizeof(ip.u));
+ break;
+ }
+
+ if (copy_to_user(uparams + n, &ip, sizeof(ip)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int tee_ioctl_supp_recv(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_recv_arg __user *uarg;
+ struct tee_param *params;
+ struct tee_ioctl_param __user *uparams;
+ u32 num_params;
+ u32 func;
+
+ if (!ctx->teedev->desc->ops->supp_recv)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg))
+ return -EINVAL;
+
+ uarg = (struct tee_iocl_supp_recv_arg __user *)(unsigned long)
+ buf.buf_ptr;
+ if (get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
+ if (rc)
+ goto out;
+
+ if (put_user(func, &uarg->func) ||
+ put_user(num_params, &uarg->num_params)) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ uparams = (struct tee_ioctl_param __user *)(uarg + 1);
+ rc = params_to_supp(ctx, uparams, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static int params_from_supp(struct tee_param *params, size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK)
+ return -EINVAL;
+
+ p->attr = ip.attr;
+ switch (ip.attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ /* Only out and in/out values can be updated */
+ p->u.value.a = ip.u.value.a;
+ p->u.value.b = ip.u.value.b;
+ p->u.value.c = ip.u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * Only the size of the memref can be updated.
+ * Since we don't have access to the original
+ * parameters here, only store the supplied size.
+ * The driver will copy the updated size into the
+ * original parameters.
+ */
+ p->u.memref.shm = NULL;
+ p->u.memref.shm_offs = 0;
+ p->u.memref.size = ip.u.memref.size;
+ break;
+ default:
+ memset(&p->u, 0, sizeof(p->u));
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tee_ioctl_supp_send(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ long rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_send_arg __user *uarg;
+ struct tee_param *params;
+ struct tee_ioctl_param __user *uparams;
+ u32 num_params;
+ u32 ret;
+
+ /* Not valid for this driver */
+ if (!ctx->teedev->desc->ops->supp_send)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_send_arg))
+ return -EINVAL;
+
+ uarg = (struct tee_iocl_supp_send_arg __user *)(unsigned long)
+ buf.buf_ptr;
+ if (get_user(ret, &uarg->ret) ||
+ get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ uparams = (struct tee_ioctl_param __user *)(uarg + 1);
+ rc = params_from_supp(params, num_params, uparams);
+ if (rc)
+ goto out;
+
+ rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct tee_context *ctx = filp->private_data;
+ void __user *uarg = (void __user *)arg;
+
+ switch (cmd) {
+ case TEE_IOC_VERSION:
+ return tee_ioctl_version(ctx, uarg);
+ case TEE_IOC_SHM_ALLOC:
+ return tee_ioctl_shm_alloc(ctx, uarg);
+ case TEE_IOC_OPEN_SESSION:
+ return tee_ioctl_open_session(ctx, uarg);
+ case TEE_IOC_INVOKE:
+ return tee_ioctl_invoke(ctx, uarg);
+ case TEE_IOC_CANCEL:
+ return tee_ioctl_cancel(ctx, uarg);
+ case TEE_IOC_CLOSE_SESSION:
+ return tee_ioctl_close_session(ctx, uarg);
+ case TEE_IOC_SUPPL_RECV:
+ return tee_ioctl_supp_recv(ctx, uarg);
+ case TEE_IOC_SUPPL_SEND:
+ return tee_ioctl_supp_send(ctx, uarg);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations tee_fops = {
+ .owner = THIS_MODULE,
+ .open = tee_open,
+ .release = tee_release,
+ .unlocked_ioctl = tee_ioctl,
+ .compat_ioctl = tee_ioctl,
+};
+
+static void tee_release_device(struct device *dev)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ mutex_destroy(&teedev->mutex);
+ kfree(teedev);
+}
+
+/**
+ * tee_device_alloc() - Allocate a new struct tee_device instance
+ * @teedesc: Descriptor for this driver
+ * @dev: Parent device for this device
+ * @pool: Shared memory pool, NULL if not used
+ * @driver_data: Private driver data for this device
+ *
+ * Allocates a new struct tee_device instance. The device is
+ * removed by tee_device_unregister().
+ *
+ * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
+ */
+struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
+ struct device *dev,
+ struct tee_shm_pool *pool,
+ void *driver_data)
+{
+ struct tee_device *teedev;
+ void *ret;
+ int rc;
+ int offs = 0;
+
+ if (!teedesc || !teedesc->name || !teedesc->ops ||
+ !teedesc->ops->get_version || !teedesc->ops->open ||
+ !teedesc->ops->release || !dev || !pool)
+ return ERR_PTR(-EINVAL);
+
+ teedev = kzalloc(sizeof(*teedev), GFP_KERNEL);
+ if (!teedev) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ if (teedesc->flags & TEE_DESC_PRIVILEGED)
+ offs = TEE_NUM_DEVICES / 2;
+
+ spin_lock(&driver_lock);
+ teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs);
+ if (teedev->id < TEE_NUM_DEVICES)
+ set_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+
+ if (teedev->id >= TEE_NUM_DEVICES) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ snprintf(teedev->name, sizeof(teedev->name), "tee%s%d",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "",
+ teedev->id - offs);
+
+ teedev->dev.class = tee_class;
+ teedev->dev.release = tee_release_device;
+ teedev->dev.parent = dev;
+
+ teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id);
+
+ rc = dev_set_name(&teedev->dev, "%s", teedev->name);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_devt;
+ }
+
+ cdev_init(&teedev->cdev, &tee_fops);
+ teedev->cdev.owner = teedesc->owner;
+ teedev->cdev.kobj.parent = &teedev->dev.kobj;
+
+ dev_set_drvdata(&teedev->dev, driver_data);
+ device_initialize(&teedev->dev);
+
+ /* 1 as tee_device_unregister() does one final tee_device_put() */
+ teedev->num_users = 1;
+ init_completion(&teedev->c_no_users);
+ mutex_init(&teedev->mutex);
+
+ teedev->desc = teedesc;
+ teedev->pool = pool;
+
+ return teedev;
+err_devt:
+ unregister_chrdev_region(teedev->dev.devt, 1);
+err:
+ dev_err(dev, "could not register %s driver\n",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client");
+ if (teedev && teedev->id < TEE_NUM_DEVICES) {
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ }
+ kfree(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_device_alloc);
+
+static ssize_t implementation_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+ struct tee_ioctl_version_data vers;
+
+ teedev->desc->ops->get_version(teedev, &vers);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id);
+}
+static DEVICE_ATTR_RO(implementation_id);
+
+static struct attribute *tee_dev_attrs[] = {
+ &dev_attr_implementation_id.attr,
+ NULL
+};
+
+static const struct attribute_group tee_dev_group = {
+ .attrs = tee_dev_attrs,
+};
+
+/**
+ * tee_device_register() - Registers a TEE device
+ * @teedev: Device to register
+ *
+ * tee_device_unregister() need to be called to remove the @teedev if
+ * this function fails.
+ *
+ * @returns < 0 on failure
+ */
+int tee_device_register(struct tee_device *teedev)
+{
+ int rc;
+
+ /*
+ * If the teedev already is registered, don't do it again. It's
+ * obviously an error to try to register twice, but if we return
+ * an error we'll force the driver to remove the teedev.
+ */
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ dev_err(&teedev->dev, "attempt to register twice\n");
+ return 0;
+ }
+
+ rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ return rc;
+ }
+
+ rc = device_add(&teedev->dev);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to device_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ goto err_device_add;
+ }
+
+ rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "failed to create sysfs attributes, err=%d\n", rc);
+ goto err_sysfs_create_group;
+ }
+
+ teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
+ return 0;
+
+err_sysfs_create_group:
+ device_del(&teedev->dev);
+err_device_add:
+ cdev_del(&teedev->cdev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_device_register);
+
+void tee_device_put(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ /* Shouldn't put in this state */
+ if (!WARN_ON(!teedev->desc)) {
+ teedev->num_users--;
+ if (!teedev->num_users) {
+ teedev->desc = NULL;
+ complete(&teedev->c_no_users);
+ }
+ }
+ mutex_unlock(&teedev->mutex);
+}
+
+bool tee_device_get(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ if (!teedev->desc) {
+ mutex_unlock(&teedev->mutex);
+ return false;
+ }
+ teedev->num_users++;
+ mutex_unlock(&teedev->mutex);
+ return true;
+}
+
+/**
+ * tee_device_unregister() - Removes a TEE device
+ * @teedev: Device to unregister
+ *
+ * This function should be called to remove the @teedev even if
+ * tee_device_register() hasn't been called yet. Does nothing if
+ * @teedev is NULL.
+ */
+void tee_device_unregister(struct tee_device *teedev)
+{
+ if (!teedev)
+ return;
+
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
+ cdev_del(&teedev->cdev);
+ device_del(&teedev->dev);
+ }
+
+ tee_device_put(teedev);
+ wait_for_completion(&teedev->c_no_users);
+
+ /*
+ * No need to take a mutex any longer now since teedev->desc was
+ * set to NULL before teedev->c_no_users was completed.
+ */
+
+ teedev->pool = NULL;
+
+ put_device(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_device_unregister);
+
+/**
+ * tee_get_drvdata() - Return driver_data pointer
+ * @teedev: Device containing the driver_data pointer
+ * @returns the driver_data pointer supplied to tee_register().
+ */
+void *tee_get_drvdata(struct tee_device *teedev)
+{
+ return dev_get_drvdata(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_get_drvdata);
+
+static int __init tee_init(void)
+{
+ int rc;
+
+ tee_class = class_create(THIS_MODULE, "tee");
+ if (IS_ERR(tee_class)) {
+ pr_err("couldn't create class\n");
+ return PTR_ERR(tee_class);
+ }
+
+ rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
+ if (rc) {
+ pr_err("failed to allocate char dev region\n");
+ class_destroy(tee_class);
+ tee_class = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit tee_exit(void)
+{
+ class_destroy(tee_class);
+ tee_class = NULL;
+ unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
+}
+
+subsys_initcall(tee_init);
+module_exit(tee_exit);
+
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("TEE Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h
new file mode 100644
index 0000000..21cb6be
--- /dev/null
+++ b/drivers/tee/tee_private.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef TEE_PRIVATE_H
+#define TEE_PRIVATE_H
+
+#include <linux/cdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct tee_device;
+
+/**
+ * struct tee_shm - shared memory object
+ * @teedev: device used to allocate the object
+ * @ctx: context using the object, if NULL the context is gone
+ * @link link element
+ * @paddr: physical address of the shared memory
+ * @kaddr: virtual address of the shared memory
+ * @size: size of shared memory
+ * @dmabuf: dmabuf used to for exporting to user space
+ * @flags: defined by TEE_SHM_* in tee_drv.h
+ * @id: unique id of a shared memory object on this device
+ */
+struct tee_shm {
+ struct tee_device *teedev;
+ struct tee_context *ctx;
+ struct list_head link;
+ phys_addr_t paddr;
+ void *kaddr;
+ size_t size;
+ struct dma_buf *dmabuf;
+ u32 flags;
+ int id;
+};
+
+struct tee_shm_pool_mgr;
+
+/**
+ * struct tee_shm_pool_mgr_ops - shared memory pool manager operations
+ * @alloc: called when allocating shared memory
+ * @free: called when freeing shared memory
+ */
+struct tee_shm_pool_mgr_ops {
+ int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm,
+ size_t size);
+ void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm);
+};
+
+/**
+ * struct tee_shm_pool_mgr - shared memory manager
+ * @ops: operations
+ * @private_data: private data for the shared memory manager
+ */
+struct tee_shm_pool_mgr {
+ const struct tee_shm_pool_mgr_ops *ops;
+ void *private_data;
+};
+
+/**
+ * struct tee_shm_pool - shared memory pool
+ * @private_mgr: pool manager for shared memory only between kernel
+ * and secure world
+ * @dma_buf_mgr: pool manager for shared memory exported to user space
+ * @destroy: called when destroying the pool
+ * @private_data: private data for the pool
+ */
+struct tee_shm_pool {
+ struct tee_shm_pool_mgr private_mgr;
+ struct tee_shm_pool_mgr dma_buf_mgr;
+ void (*destroy)(struct tee_shm_pool *pool);
+ void *private_data;
+};
+
+#define TEE_DEVICE_FLAG_REGISTERED 0x1
+#define TEE_MAX_DEV_NAME_LEN 32
+
+/**
+ * struct tee_device - TEE Device representation
+ * @name: name of device
+ * @desc: description of device
+ * @id: unique id of device
+ * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above
+ * @dev: embedded basic device structure
+ * @cdev: embedded cdev
+ * @num_users: number of active users of this device
+ * @c_no_user: completion used when unregistering the device
+ * @mutex: mutex protecting @num_users and @idr
+ * @idr: register of shared memory object allocated on this device
+ * @pool: shared memory pool
+ */
+struct tee_device {
+ char name[TEE_MAX_DEV_NAME_LEN];
+ const struct tee_desc *desc;
+ int id;
+ unsigned int flags;
+
+ struct device dev;
+ struct cdev cdev;
+
+ size_t num_users;
+ struct completion c_no_users;
+ struct mutex mutex; /* protects num_users and idr */
+
+ struct idr idr;
+ struct tee_shm_pool *pool;
+};
+
+int tee_shm_init(void);
+
+int tee_shm_get_fd(struct tee_shm *shm);
+
+bool tee_device_get(struct tee_device *teedev);
+void tee_device_put(struct tee_device *teedev);
+
+#endif /*TEE_PRIVATE_H*/
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
new file mode 100644
index 0000000..9fd501c
--- /dev/null
+++ b/drivers/tee/tee_shm.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/fdtable.h>
+#include <linux/idr.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+static void tee_shm_release(struct tee_shm *shm)
+{
+ struct tee_device *teedev = shm->teedev;
+ struct tee_shm_pool_mgr *poolm;
+
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ if (shm->ctx)
+ list_del(&shm->link);
+ mutex_unlock(&teedev->mutex);
+
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ poolm = &teedev->pool->dma_buf_mgr;
+ else
+ poolm = &teedev->pool->private_mgr;
+
+ poolm->ops->free(poolm, shm);
+ kfree(shm);
+
+ tee_device_put(teedev);
+}
+
+static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
+ *attach, enum dma_data_direction dir)
+{
+ return NULL;
+}
+
+static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *table,
+ enum dma_data_direction dir)
+{
+}
+
+static void tee_shm_op_release(struct dma_buf *dmabuf)
+{
+ struct tee_shm *shm = dmabuf->priv;
+
+ tee_shm_release(shm);
+}
+
+static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+ struct tee_shm *shm = dmabuf->priv;
+ size_t size = vma->vm_end - vma->vm_start;
+
+ return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+}
+
+static struct dma_buf_ops tee_shm_dma_buf_ops = {
+ .map_dma_buf = tee_shm_op_map_dma_buf,
+ .unmap_dma_buf = tee_shm_op_unmap_dma_buf,
+ .release = tee_shm_op_release,
+ .kmap_atomic = tee_shm_op_kmap_atomic,
+ .kmap = tee_shm_op_kmap,
+ .mmap = tee_shm_op_mmap,
+};
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
+ * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
+ * associated with a dma-buf handle, else driver private memory.
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct tee_shm_pool_mgr *poolm = NULL;
+ struct tee_shm *shm;
+ void *ret;
+ int rc;
+
+ if (!(flags & TEE_SHM_MAPPED)) {
+ dev_err(teedev->dev.parent,
+ "only mapped allocations supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
+ dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!tee_device_get(teedev))
+ return ERR_PTR(-EINVAL);
+
+ if (!teedev->pool) {
+ /* teedev has been detached from driver */
+ ret = ERR_PTR(-EINVAL);
+ goto err_dev_put;
+ }
+
+ shm = kzalloc(sizeof(*shm), GFP_KERNEL);
+ if (!shm) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err_dev_put;
+ }
+
+ shm->flags = flags;
+ shm->teedev = teedev;
+ shm->ctx = ctx;
+ if (flags & TEE_SHM_DMA_BUF)
+ poolm = &teedev->pool->dma_buf_mgr;
+ else
+ poolm = &teedev->pool->private_mgr;
+
+ rc = poolm->ops->alloc(poolm, shm, size);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_kfree;
+ }
+
+ mutex_lock(&teedev->mutex);
+ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+ mutex_unlock(&teedev->mutex);
+ if (shm->id < 0) {
+ ret = ERR_PTR(shm->id);
+ goto err_pool_free;
+ }
+
+ if (flags & TEE_SHM_DMA_BUF) {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = shm->size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = shm;
+
+ shm->dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(shm->dmabuf)) {
+ ret = ERR_CAST(shm->dmabuf);
+ goto err_rem;
+ }
+ }
+ mutex_lock(&teedev->mutex);
+ list_add_tail(&shm->link, &ctx->list_shm);
+ mutex_unlock(&teedev->mutex);
+
+ return shm;
+err_rem:
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ mutex_unlock(&teedev->mutex);
+err_pool_free:
+ poolm->ops->free(poolm, shm);
+err_kfree:
+ kfree(shm);
+err_dev_put:
+ tee_device_put(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_shm_alloc);
+
+/**
+ * tee_shm_get_fd() - Increase reference count and return file descriptor
+ * @shm: Shared memory handle
+ * @returns user space file descriptor to shared memory
+ */
+int tee_shm_get_fd(struct tee_shm *shm)
+{
+ u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF;
+ int fd;
+
+ if ((shm->flags & req_flags) != req_flags)
+ return -EINVAL;
+
+ fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
+ if (fd >= 0)
+ get_dma_buf(shm->dmabuf);
+ return fd;
+}
+
+/**
+ * tee_shm_free() - Free shared memory
+ * @shm: Handle to shared memory to free
+ */
+void tee_shm_free(struct tee_shm *shm)
+{
+ /*
+ * dma_buf_put() decreases the dmabuf reference counter and will
+ * call tee_shm_release() when the last reference is gone.
+ *
+ * In the case of driver private memory we call tee_shm_release
+ * directly instead as it doesn't have a reference counter.
+ */
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+ else
+ tee_shm_release(shm);
+}
+EXPORT_SYMBOL_GPL(tee_shm_free);
+
+/**
+ * tee_shm_va2pa() - Get physical address of a virtual address
+ * @shm: Shared memory handle
+ * @va: Virtual address to tranlsate
+ * @pa: Returned physical address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
+{
+ /* Check that we're in the range of the shm */
+ if ((char *)va < (char *)shm->kaddr)
+ return -EINVAL;
+ if ((char *)va >= ((char *)shm->kaddr + shm->size))
+ return -EINVAL;
+
+ return tee_shm_get_pa(
+ shm, (unsigned long)va - (unsigned long)shm->kaddr, pa);
+}
+EXPORT_SYMBOL_GPL(tee_shm_va2pa);
+
+/**
+ * tee_shm_pa2va() - Get virtual address of a physical address
+ * @shm: Shared memory handle
+ * @pa: Physical address to tranlsate
+ * @va: Returned virtual address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
+{
+ /* Check that we're in the range of the shm */
+ if (pa < shm->paddr)
+ return -EINVAL;
+ if (pa >= (shm->paddr + shm->size))
+ return -EINVAL;
+
+ if (va) {
+ void *v = tee_shm_get_va(shm, pa - shm->paddr);
+
+ if (IS_ERR(v))
+ return PTR_ERR(v);
+ *va = v;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pa2va);
+
+/**
+ * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @returns virtual address of the shared memory + offs if offs is within
+ * the bounds of this shared memory, else an ERR_PTR
+ */
+void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
+{
+ if (offs >= shm->size)
+ return ERR_PTR(-EINVAL);
+ return (char *)shm->kaddr + offs;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_va);
+
+/**
+ * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @pa: Physical address to return
+ * @returns 0 if offs is within the bounds of this shared memory, else an
+ * error code.
+ */
+int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa)
+{
+ if (offs >= shm->size)
+ return -EINVAL;
+ if (pa)
+ *pa = shm->paddr + offs;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_pa);
+
+/**
+ * tee_shm_get_from_id() - Find shared memory object and increase referece count
+ * @ctx: Context owning the shared memory
+ * @id: Id of shared memory object
+ * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
+ */
+struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
+{
+ struct tee_device *teedev;
+ struct tee_shm *shm;
+
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+
+ teedev = ctx->teedev;
+ mutex_lock(&teedev->mutex);
+ shm = idr_find(&teedev->idr, id);
+ if (!shm || shm->ctx != ctx)
+ shm = ERR_PTR(-EINVAL);
+ else if (shm->flags & TEE_SHM_DMA_BUF)
+ get_dma_buf(shm->dmabuf);
+ mutex_unlock(&teedev->mutex);
+ return shm;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
+
+/**
+ * tee_shm_get_id() - Get id of a shared memory object
+ * @shm: Shared memory handle
+ * @returns id
+ */
+int tee_shm_get_id(struct tee_shm *shm)
+{
+ return shm->id;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_id);
+
+/**
+ * tee_shm_put() - Decrease reference count on a shared memory handle
+ * @shm: Shared memory handle
+ */
+void tee_shm_put(struct tee_shm *shm)
+{
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+}
+EXPORT_SYMBOL_GPL(tee_shm_put);
diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c
new file mode 100644
index 0000000..3cb0ad0
--- /dev/null
+++ b/drivers/tee/tee_shm_pool.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm, size_t size)
+{
+ unsigned long va;
+ struct gen_pool *genpool = poolm->private_data;
+ size_t s = roundup(size, 1 << genpool->min_alloc_order);
+
+ va = gen_pool_alloc(genpool, s);
+ if (!va)
+ return -ENOMEM;
+
+ memset((void *)va, 0, s);
+ shm->kaddr = (void *)va;
+ shm->paddr = gen_pool_virt_to_phys(genpool, va);
+ shm->size = s;
+ return 0;
+}
+
+static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm)
+{
+ gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr,
+ shm->size);
+ shm->kaddr = NULL;
+}
+
+static const struct tee_shm_pool_mgr_ops pool_ops_generic = {
+ .alloc = pool_op_gen_alloc,
+ .free = pool_op_gen_free,
+};
+
+static void pool_res_mem_destroy(struct tee_shm_pool *pool)
+{
+ gen_pool_destroy(pool->private_mgr.private_data);
+ gen_pool_destroy(pool->dma_buf_mgr.private_data);
+}
+
+static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
+ struct tee_shm_pool_mem_info *info,
+ int min_alloc_order)
+{
+ size_t page_mask = PAGE_SIZE - 1;
+ struct gen_pool *genpool = NULL;
+ int rc;
+
+ /*
+ * Start and end must be page aligned
+ */
+ if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
+ (info->size & page_mask))
+ return -EINVAL;
+
+ genpool = gen_pool_create(min_alloc_order, -1);
+ if (!genpool)
+ return -ENOMEM;
+
+ gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
+ rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
+ -1);
+ if (rc) {
+ gen_pool_destroy(genpool);
+ return rc;
+ }
+
+ mgr->private_data = genpool;
+ mgr->ops = &pool_ops_generic;
+ return 0;
+}
+
+/**
+ * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
+ * memory range
+ * @dev: Device allocating the pool
+ * @priv_info: Information for driver private shared memory pool
+ * @dmabuf_info: Information for dma-buf shared memory pool
+ *
+ * Start and end of pools will must be page aligned.
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *
+tee_shm_pool_alloc_res_mem(struct device *dev,
+ struct tee_shm_pool_mem_info *priv_info,
+ struct tee_shm_pool_mem_info *dmabuf_info)
+{
+ struct tee_shm_pool *pool = NULL;
+ int ret;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * Create the pool for driver private shared memory
+ */
+ ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
+ 3 /* 8 byte aligned */);
+ if (ret)
+ goto err;
+
+ /*
+ * Create the pool for dma_buf shared memory
+ */
+ ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info,
+ PAGE_SHIFT);
+ if (ret)
+ goto err;
+
+ pool->destroy = pool_res_mem_destroy;
+ return pool;
+err:
+ if (ret == -ENOMEM)
+ dev_err(dev, "can't allocate memory for res_mem shared memory pool\n");
+ if (pool && pool->private_mgr.private_data)
+ gen_pool_destroy(pool->private_mgr.private_data);
+ kfree(pool);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+
+/**
+ * tee_shm_pool_free() - Free a shared memory pool
+ * @pool: The shared memory pool to free
+ *
+ * There must be no remaining shared memory allocated from this pool when
+ * this function is called.
+ */
+void tee_shm_pool_free(struct tee_shm_pool *pool)
+{
+ pool->destroy(pool);
+ kfree(pool);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_free);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
new file mode 100644
index 0000000..f5d5f45
--- /dev/null
+++ b/include/linux/tee_drv.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __TEE_DRV_H
+#define __TEE_DRV_H
+
+#include <linux/types.h>
+#include <linux/idr.h>
+#include <linux/list.h>
+#include <linux/tee.h>
+
+/*
+ * The file describes the API provided by the generic TEE driver to the
+ * specific TEE driver.
+ */
+
+#define TEE_SHM_MAPPED 0x1 /* Memory mapped by the kernel */
+#define TEE_SHM_DMA_BUF 0x2 /* Memory with dma-buf handle */
+
+struct tee_device;
+struct tee_shm;
+struct tee_shm_pool;
+
+/**
+ * struct tee_context - driver specific context on file pointer data
+ * @teedev: pointer to this drivers struct tee_device
+ * @list_shm: List of shared memory object owned by this context
+ * @data: driver specific context data, managed by the driver
+ */
+struct tee_context {
+ struct tee_device *teedev;
+ struct list_head list_shm;
+ void *data;
+};
+
+struct tee_param_memref {
+ size_t shm_offs;
+ size_t size;
+ struct tee_shm *shm;
+};
+
+struct tee_param_value {
+ u64 a;
+ u64 b;
+ u64 c;
+};
+
+struct tee_param {
+ u64 attr;
+ union {
+ struct tee_param_memref memref;
+ struct tee_param_value value;
+ } u;
+};
+
+/**
+ * struct tee_driver_ops - driver operations vtable
+ * @get_version: returns version of driver
+ * @open: called when the device file is opened
+ * @release: release this open file
+ * @open_session: open a new session
+ * @close_session: close a session
+ * @invoke_func: invoke a trusted function
+ * @cancel_req: request cancel of an ongoing invoke or open
+ * @supp_revc: called for supplicant to get a command
+ * @supp_send: called for supplicant to send a response
+ */
+struct tee_driver_ops {
+ void (*get_version)(struct tee_device *teedev,
+ struct tee_ioctl_version_data *vers);
+ int (*open)(struct tee_context *ctx);
+ void (*release)(struct tee_context *ctx);
+ int (*open_session)(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param);
+ int (*close_session)(struct tee_context *ctx, u32 session);
+ int (*invoke_func)(struct tee_context *ctx,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param);
+ int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session);
+ int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param);
+ int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param);
+};
+
+/**
+ * struct tee_desc - Describes the TEE driver to the subsystem
+ * @name: name of driver
+ * @ops: driver operations vtable
+ * @owner: module providing the driver
+ * @flags: Extra properties of driver, defined by TEE_DESC_* below
+ */
+#define TEE_DESC_PRIVILEGED 0x1
+struct tee_desc {
+ const char *name;
+ const struct tee_driver_ops *ops;
+ struct module *owner;
+ u32 flags;
+};
+
+/**
+ * tee_device_alloc() - Allocate a new struct tee_device instance
+ * @teedesc: Descriptor for this driver
+ * @dev: Parent device for this device
+ * @pool: Shared memory pool, NULL if not used
+ * @driver_data: Private driver data for this device
+ *
+ * Allocates a new struct tee_device instance. The device is
+ * removed by tee_device_unregister().
+ *
+ * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
+ */
+struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
+ struct device *dev,
+ struct tee_shm_pool *pool,
+ void *driver_data);
+
+/**
+ * tee_device_register() - Registers a TEE device
+ * @teedev: Device to register
+ *
+ * tee_device_unregister() need to be called to remove the @teedev if
+ * this function fails.
+ *
+ * @returns < 0 on failure
+ */
+int tee_device_register(struct tee_device *teedev);
+
+/**
+ * tee_device_unregister() - Removes a TEE device
+ * @teedev: Device to unregister
+ *
+ * This function should be called to remove the @teedev even if
+ * tee_device_register() hasn't been called yet. Does nothing if
+ * @teedev is NULL.
+ */
+void tee_device_unregister(struct tee_device *teedev);
+
+/**
+ * struct tee_shm_pool_mem_info - holds information needed to create a shared
+ * memory pool
+ * @vaddr: Virtual address of start of pool
+ * @paddr: Physical address of start of pool
+ * @size: Size in bytes of the pool
+ */
+struct tee_shm_pool_mem_info {
+ unsigned long vaddr;
+ phys_addr_t paddr;
+ size_t size;
+};
+
+/**
+ * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
+ * memory range
+ * @dev: Device allocating the pool
+ * @priv_info: Information for driver private shared memory pool
+ * @dmabuf_info: Information for dma-buf shared memory pool
+ *
+ * Start and end of pools will must be page aligned.
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *
+tee_shm_pool_alloc_res_mem(struct device *dev,
+ struct tee_shm_pool_mem_info *priv_info,
+ struct tee_shm_pool_mem_info *dmabuf_info);
+
+/**
+ * tee_shm_pool_free() - Free a shared memory pool
+ * @pool: The shared memory pool to free
+ *
+ * The must be no remaining shared memory allocated from this pool when
+ * this function is called.
+ */
+void tee_shm_pool_free(struct tee_shm_pool *pool);
+
+/**
+ * tee_get_drvdata() - Return driver_data pointer
+ * @returns the driver_data pointer supplied to tee_register().
+ */
+void *tee_get_drvdata(struct tee_device *teedev);
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If
+ * TEE_SHM_DMA_BUF global shared memory will be allocated and associated
+ * with a dma-buf handle, else driver private memory.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags);
+
+/**
+ * tee_shm_free() - Free shared memory
+ * @shm: Handle to shared memory to free
+ */
+void tee_shm_free(struct tee_shm *shm);
+
+/**
+ * tee_shm_put() - Decrease reference count on a shared memory handle
+ * @shm: Shared memory handle
+ */
+void tee_shm_put(struct tee_shm *shm);
+
+/**
+ * tee_shm_va2pa() - Get physical address of a virtual address
+ * @shm: Shared memory handle
+ * @va: Virtual address to tranlsate
+ * @pa: Returned physical address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa);
+
+/**
+ * tee_shm_pa2va() - Get virtual address of a physical address
+ * @shm: Shared memory handle
+ * @pa: Physical address to tranlsate
+ * @va: Returned virtual address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va);
+
+/**
+ * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @returns virtual address of the shared memory + offs if offs is within
+ * the bounds of this shared memory, else an ERR_PTR
+ */
+void *tee_shm_get_va(struct tee_shm *shm, size_t offs);
+
+/**
+ * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @pa: Physical address to return
+ * @returns 0 if offs is within the bounds of this shared memory, else an
+ * error code.
+ */
+int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa);
+
+/**
+ * tee_shm_get_id() - Get id of a shared memory object
+ * @shm: Shared memory handle
+ * @returns id
+ */
+int tee_shm_get_id(struct tee_shm *shm);
+
+/**
+ * tee_shm_get_from_id() - Find shared memory object and increase referece count
+ * @ctx: Context owning the shared memory
+ * @id: Id of shared memory object
+ * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
+ */
+struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id);
+
+#endif /*__TEE_DRV_H*/
diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
new file mode 100644
index 0000000..ddc476e
--- /dev/null
+++ b/include/uapi/linux/tee.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TEE_H
+#define __TEE_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/*
+ * This file describes the API provided by a TEE driver to user space.
+ *
+ * Each TEE driver defines a TEE specific protocol which is used for the
+ * data passed back and forth using TEE_IOC_CMD.
+ */
+
+/* Helpers to make the ioctl defines */
+#define TEE_IOC_MAGIC 0xa4
+#define TEE_IOC_BASE 0
+
+/* Flags relating to shared memory */
+#define TEE_IOCTL_SHM_MAPPED 0x1 /* memory mapped in normal world */
+#define TEE_IOCTL_SHM_DMA_BUF 0x2 /* dma-buf handle on shared memory */
+
+#define TEE_MAX_ARG_SIZE 1024
+
+#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */
+
+/*
+ * TEE Implementation ID
+ */
+#define TEE_IMPL_ID_OPTEE 1
+
+/*
+ * OP-TEE specific capabilities
+ */
+#define TEE_OPTEE_CAP_TZ (1 << 0)
+
+/**
+ * struct tee_ioctl_version_data - TEE version
+ * @impl_id: [out] TEE implementation id
+ * @impl_caps: [out] Implementation specific capabilities
+ * @gen_caps: [out] Generic capabilities, defined by TEE_GEN_CAPS_* above
+ *
+ * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above.
+ * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_*
+ * is valid when @impl_id == TEE_IMPL_ID_OPTEE.
+ */
+struct tee_ioctl_version_data {
+ __u32 impl_id;
+ __u32 impl_caps;
+ __u32 gen_caps;
+};
+
+/**
+ * TEE_IOC_VERSION - query version of TEE
+ *
+ * Takes a tee_ioctl_version_data struct and returns with the TEE version
+ * data filled in.
+ */
+#define TEE_IOC_VERSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \
+ struct tee_ioctl_version_data)
+
+/**
+ * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument
+ * @size: [in/out] Size of shared memory to allocate
+ * @flags: [in/out] Flags to/from allocation.
+ * @id: [out] Identifier of the shared memory
+ *
+ * The flags field should currently be zero as input. Updated by the call
+ * with actual flags as defined by TEE_IOCTL_SHM_* above.
+ * This structure is used as argument for TEE_IOC_SHM_ALLOC below.
+ */
+struct tee_ioctl_shm_alloc_data {
+ __u64 size;
+ __u32 flags;
+ __s32 id;
+};
+
+/**
+ * TEE_IOC_SHM_ALLOC - allocate shared memory
+ *
+ * Allocates shared memory between the user space process and secure OS.
+ *
+ * Returns a file descriptor on success or < 0 on failure
+ *
+ * The returned file descriptor is used to map the shared memory into user
+ * space. The shared memory is freed when the descriptor is closed and the
+ * memory is unmapped.
+ */
+#define TEE_IOC_SHM_ALLOC _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \
+ struct tee_ioctl_shm_alloc_data)
+
+/**
+ * struct tee_ioctl_buf_data - Variable sized buffer
+ * @buf_ptr: [in] A __user pointer to a buffer
+ * @buf_len: [in] Length of the buffer above
+ *
+ * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE,
+ * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below.
+ */
+struct tee_ioctl_buf_data {
+ __u64 buf_ptr;
+ __u64 buf_len;
+};
+
+/*
+ * Attributes for struct tee_ioctl_param, selects field in the union
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_NONE 0 /* parameter not used */
+
+/*
+ * These defines value parameters (struct tee_ioctl_param_value)
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT 1
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT 2
+#define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT 3 /* input and output */
+
+/*
+ * These defines shared memory reference parameters (struct
+ * tee_ioctl_param_memref)
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT 5
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */
+
+/*
+ * Mask for the type part of the attribute, leaves room for more types
+ */
+#define TEE_IOCTL_PARAM_ATTR_TYPE_MASK 0xff
+
+/*
+ * Matches TEEC_LOGIN_* in GP TEE Client API
+ * Are only defined for GP compliant TEEs
+ */
+#define TEE_IOCTL_LOGIN_PUBLIC 0
+#define TEE_IOCTL_LOGIN_USER 1
+#define TEE_IOCTL_LOGIN_GROUP 2
+#define TEE_IOCTL_LOGIN_APPLICATION 4
+#define TEE_IOCTL_LOGIN_USER_APPLICATION 5
+#define TEE_IOCTL_LOGIN_GROUP_APPLICATION 6
+
+/**
+ * struct tee_ioctl_param_memref - memory reference
+ * @shm_offs: Offset into the shared memory object
+ * @size: Size of the buffer
+ * @shm_id: Shared memory identifier
+ *
+ * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an
+ * identifier representing the shared memory object. A memref can reference
+ * a part of a shared memory by specifying an offset (@shm_offs) and @size
+ * of the object. To supply the entire shared memory object set @shm_offs
+ * to 0 and @size to the previously returned size of the object.
+ */
+struct tee_ioctl_param_memref {
+ __u64 shm_offs;
+ __u64 size;
+ __s64 shm_id;
+};
+
+/**
+ * struct tee_ioctl_param_value - values
+ * @a: first value
+ * @b: second value
+ * @c: third value
+ *
+ * Value parameters are passed unchecked to the destination
+ */
+struct tee_ioctl_param_value {
+ __u64 a;
+ __u64 b;
+ __u64 c;
+};
+
+/**
+ * struct tee_ioctl_param - parameter
+ * @attr: attributes
+ * @memref: a memory reference
+ * @value: a value
+ *
+ * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in
+ * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and
+ * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE
+ * indicates that none of the members are used.
+ */
+struct tee_ioctl_param {
+ __u64 attr;
+ union {
+ struct tee_ioctl_param_memref memref;
+ struct tee_ioctl_param_value value;
+ } u;
+};
+
+#define TEE_IOCTL_UUID_LEN 16
+
+/**
+ * struct tee_ioctl_open_session_arg - Open session argument
+ * @uuid: [in] UUID of the Trusted Application
+ * @clnt_uuid: [in] UUID of client
+ * @clnt_login: [in] Login class of client, TEE_IOCTL_LOGIN_* above
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @session: [out] Session id
+ * @ret: [out] return value
+ * @ret_origin [out] origin of the return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_ioctl_open_session_arg {
+ __u8 uuid[TEE_IOCTL_UUID_LEN];
+ __u8 clnt_uuid[TEE_IOCTL_UUID_LEN];
+ __u32 clnt_login;
+ __u32 cancel_id;
+ __u32 session;
+ __u32 ret;
+ __u32 ret_origin;
+ __u32 num_params;
+ /*
+ * this struct is 8 byte aligned since the 'struct tee_ioctl_param'
+ * which follows requires 8 byte alignment.
+ *
+ * Commented out element used to visualize the layout dynamic part
+ * of the struct. This field is not available at all if
+ * num_params == 0.
+ *
+ * struct tee_ioctl_param params[num_params];
+ */
+} __aligned(8);
+
+/**
+ * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_ioctl_open_session_arg followed by any array of struct
+ * tee_ioctl_param
+ */
+#define TEE_IOC_OPEN_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted
+ * Application
+ * @func: [in] Trusted Application function, specific to the TA
+ * @session: [in] Session id
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @ret: [out] return value
+ * @ret_origin [out] origin of the return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_ioctl_invoke_arg {
+ __u32 func;
+ __u32 session;
+ __u32 cancel_id;
+ __u32 ret;
+ __u32 ret_origin;
+ __u32 num_params;
+ /*
+ * this struct is 8 byte aligned since the 'struct tee_ioctl_param'
+ * which follows requires 8 byte alignment.
+ *
+ * Commented out element used to visualize the layout dynamic part
+ * of the struct. This field is not available at all if
+ * num_params == 0.
+ *
+ * struct tee_ioctl_param params[num_params];
+ */
+} __aligned(8);
+
+/**
+ * TEE_IOC_INVOKE - Invokes a function in a Trusted Application
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_invoke_func_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl
+ * @cancel_id: [in] Cancellation id, a unique value to identify this request
+ * @session: [in] Session id, if the session is opened, else set to 0
+ */
+struct tee_ioctl_cancel_arg {
+ __u32 cancel_id;
+ __u32 session;
+};
+
+/**
+ * TEE_IOC_CANCEL - Cancels an open session or invoke
+ */
+#define TEE_IOC_CANCEL _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \
+ struct tee_ioctl_cancel_arg)
+
+/**
+ * struct tee_ioctl_close_session_arg - Closes an open session
+ * @session: [in] Session id
+ */
+struct tee_ioctl_close_session_arg {
+ __u32 session;
+};
+
+/**
+ * TEE_IOC_CLOSE_SESSION - Closes a session
+ */
+#define TEE_IOC_CLOSE_SESSION _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \
+ struct tee_ioctl_close_session_arg)
+
+/**
+ * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function
+ * @func: [in] supplicant function
+ * @num_params [in/out] number of parameters following this struct
+ *
+ * @num_params is the number of params that tee-supplicant has room to
+ * receive when input, @num_params is the number of actual params
+ * tee-supplicant receives when output.
+ */
+struct tee_iocl_supp_recv_arg {
+ __u32 func;
+ __u32 num_params;
+ /*
+ * this struct is 8 byte aligned since the 'struct tee_ioctl_param'
+ * which follows requires 8 byte alignment.
+ *
+ * Commented out element used to visualize the layout dynamic part
+ * of the struct. This field is not available at all if
+ * num_params == 0.
+ *
+ * struct tee_ioctl_param params[num_params];
+ */
+} __aligned(8);
+
+/**
+ * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_iocl_supp_recv_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_SUPPL_RECV _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \
+ struct tee_ioctl_buf_data)
+
+/**
+ * struct tee_iocl_supp_send_arg - Send a response to a received request
+ * @ret: [out] return value
+ * @num_params [in] number of parameters following this struct
+ */
+struct tee_iocl_supp_send_arg {
+ __u32 ret;
+ __u32 num_params;
+ /*
+ * this struct is 8 byte aligned since the 'struct tee_ioctl_param'
+ * which follows requires 8 byte alignment.
+ *
+ * Commented out element used to visualize the layout dynamic part
+ * of the struct. This field is not available@all if
+ * num_params == 0.
+ *
+ * struct tee_ioctl_param params[num_params];
+ */
+} __aligned(8);
+/**
+ * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function
+ *
+ * Takes a struct tee_ioctl_buf_data which contains a struct
+ * tee_iocl_supp_send_arg followed by any array of struct tee_param
+ */
+#define TEE_IOC_SUPPL_SEND _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \
+ struct tee_ioctl_buf_data)
+
+/*
+ * Five syscalls are used when communicating with the TEE driver.
+ * open(): opens the device associated with the driver
+ * ioctl(): as described above operating on the file descriptor from open()
+ * close(): two cases
+ * - closes the device file descriptor
+ * - closes a file descriptor connected to allocated shared memory
+ * mmap(): maps shared memory into user space using information from struct
+ * tee_ioctl_shm_alloc_data
+ * munmap(): unmaps previously shared memory
+ */
+
+#endif /*__TEE_H*/
--
1.9.1
^ permalink raw reply related
* [PATCH v12 RESEND 1/4] dt/bindings: add bindings for optee
From: Jens Wiklander @ 2016-10-28 10:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477649984-16777-1-git-send-email-jens.wiklander@linaro.org>
Introduces linaro prefix and adds bindings for ARM TrustZone based OP-TEE
implementation.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
---
.../bindings/arm/firmware/linaro,optee-tz.txt | 31 ++++++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.txt | 1 +
2 files changed, 32 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
diff --git a/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
new file mode 100644
index 0000000..d38834c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
@@ -0,0 +1,31 @@
+OP-TEE Device Tree Bindings
+
+OP-TEE is a piece of software using hardware features to provide a Trusted
+Execution Environment. The security can be provided with ARM TrustZone, but
+also by virtualization or a separate chip.
+
+We're using "linaro" as the first part of the compatible property for
+the reference implementation maintained by Linaro.
+
+* OP-TEE based on ARM TrustZone required properties:
+
+- compatible : should contain "linaro,optee-tz"
+
+- method : The method of calling the OP-TEE Trusted OS. Permitted
+ values are:
+
+ "smc" : SMC #0, with the register assignments specified
+ in drivers/tee/optee/optee_smc.h
+
+ "hvc" : HVC #0, with the register assignments specified
+ in drivers/tee/optee/optee_smc.h
+
+
+
+Example:
+ firmware {
+ optee {
+ compatible = "linaro,optee-tz";
+ method = "smc";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index f0a48ea..6ab5d04 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -155,6 +155,7 @@ lacie LaCie
lantiq Lantiq Semiconductor
lenovo Lenovo Group Ltd.
lg LG Corporation
+linaro Linaro Limited
linux Linux-specific binding
lltc Linear Technology Corporation
lsi LSI Corp. (LSI Logic)
--
1.9.1
^ permalink raw reply related
* [PATCH v12 RESEND 0/4] generic TEE subsystem
From: Jens Wiklander @ 2016-10-28 10:19 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This patch set introduces a generic TEE subsystem. The TEE subsystem will
contain drivers for various TEE implementations. A TEE (Trusted Execution
Environment) is a trusted OS running in some secure environment, for
example, TrustZone on ARM CPUs, or a separate secure co-processor etc.
Regarding use cases, TrustZone has traditionally been used for
offloading secure tasks to the secure world. Examples include:
- Secure key handling where the OS may or may not have direct access to key
material.
- E-commerce and payment technologies. Credentials, credit card numbers etc
could be stored in a more secure environment.
- Trusted User Interface (TUI) to ensure that no-one can snoop PIN-codes
etc.
- Secure boot to ensure that loaded binaries haven?t been tampered with.
It?s not strictly needed for secure boot, but you could enhance security
by leveraging a TEE during boot.
- Digital Rights Management (DRM), the studios provides content with
different resolution depending on the security of the device. Higher
security means higher resolution.
A TEE could also be used in existing and new technologies. For example IMA
(Integrity Measurement Architecture) which has been in the kernel for quite
a while. Today you can enhance security by using a TPM-chip to sign the IMA
measurement list. This is something that you also could do by leveraging a
TEE.
Another example could be in 2-factor authentication which is becoming
increasingly more important. FIDO (https://fidoalliance.org) for example
are using public key cryptography in their 2-factor authentication standard
(U2F). With FIDO, a private and public key pair will be generated for every
site you visit and the private key should never leave the local device.
This is an example where you could use secure storage in a TEE for the
private key.
Today you will find a quite a few different out of tree implementations of
TEE drivers which tends to fragment the TEE ecosystem and development. We
think it would be a good idea to have a generic TEE driver integrated in
the kernel which would serve as a base for several different TEE solutions,
no matter if they are on-chip like TrustZone or if they are on a separate
crypto co-processor.
To develop this TEE subsystem we have been using the open source TEE called
OP-TEE (https://github.com/OP-TEE/optee_os) and therefore this would be the
first TEE solution supported by this new subsystem. OP-TEE is a
GlobalPlatform compliant TEE, however this TEE subsystem is not limited to
only GlobalPlatform TEEs, instead we have tried to design it so that it
should work with other TEE solutions also.
"tee: generic TEE subsystem" brings in the generic TEE subsystem which
helps when writing a driver for a specific TEE, for example, OP-TEE.
"tee: add OP-TEE driver" is an OP-TEE driver which uses the subsystem to do
its work.
This patch set has been prepared in cooperation with Javier Gonz?lez who
proposed "Generic TrustZone Driver in Linux Kernel" patches 28 Nov 2014,
https://lwn.net/Articles/623380/ . We've since then changed the scope to
TEE instead of TrustZone.
We have discussed the design on tee-dev at lists.linaro.org (archive at
https://lists.linaro.org/pipermail/tee-dev/) with people from other
companies, including Valentin Manea <valentin.manea@huawei.com>,
Emmanuel MICHEL <emmanuel.michel@st.com>,
Jean-michel DELORME <jean-michel.delorme@st.com>,
and Joakim Bech <joakim.bech@linaro.org>. Our main concern has been to
agree on something that is generic enough to support many different
TEEs while still keeping the interface together.
v12-resend:
* Rebased on v4.9-rc2
v12:
* Rebased on v4.8-rc5
* Addressed review comments from Andrew F. Davis
* Removed Acked-by: Andreas Dannenberg <dannenberg@ti.com> as the
mail bounces
* Bugfix possible null dereference in error cleanup path of
optee_probe().
* Bugfix optee_from_msg_param() when calculating offset of memref
into a shared memory object
v11:
* Rebased on v4.8-rc3
* Addressed review comments from Nishanth Menon
* Made the TEE framework available as a loadable module.
* Reviewed-by: Javier Gonz?lez <javier@javigon.com>
* Zeroes shared memory on allocation to avoid information leakage
* Links shared memory objects to context to avoid stealing of shared memory
object from an unrelated process
* Allow RPC interruption if supplicant is unavailable
v10:
* Rebased on v4.7-rc1
* Addressed private review comments from Nishanth Menon
* Optee driver only accepts one supplicant process on the privileged device
* Optee driver avoids long delayed releases of shm objects
* Added more comments on functions and structs
v9:
* Rebased on v4.6-rc1
* Acked-by: Andreas Dannenberg <dannenberg@ti.com>
* Addressed comments from Al Viro how file descriptors are passed to
user space
* Addressed comments from Randy Dunlap on documentation
* Changed license for include/uapi/linux/tee.h
v8:
* Rebased on v4.5-rc3
* dt/bindings: add bindings for optee
Acked-by: Rob Herring <robh@kernel.org>
* Fixes build error for X86
* Fixes spell error in "dt/bindings: add bindings for optee"
v7:
* Rebased on v4.5-rc2
* Moved the ARM SMC Calling Convention support into a separate patch
set, which is now merged
v6:
* Rebased on v4.3-rc7
* Changed smccc interface to let the compiler marshal most of the
parameters
* Added ARCH64 capability for smccc interface
* Changed the PSCI firmware calls (both arm and arm64) to use the new
generic smccc interface instead instead of own assembly functions.
* Move optee DT bindings to below arm/firmware
* Defines method for OP-TEE driver to call secure world in DT, smc or hvc
* Exposes implementation id of a TEE driver in sysfs
to easily spawn corresponding tee-supplicant when device is ready
* Update OP-TEE Message Protocol to better cope with fragmented physical
memory
* Read time directly from OP-TEE driver instead of forwarding the RPC
request to tee-supplicant
v5:
* Replaced kref reference counting for the device with a size_t instead as
the counter is always protected by a mutex
v4:
* Rebased on 4.1
* Redesigned the synchronization around entry exit of normal SMC
* Replaced rwsem on the driver instance with kref and completion since
rwsem wasn't intended to be used in this way
* Expanded the TEE_IOCTL_PARAM_ATTR_TYPE_MASK to make room for
future additional parameter types
* Documents TEE subsystem and OP-TEE driver
* Replaced TEE_IOC_CMD with TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE,
TEE_IOC_CANCEL and TEE_IOC_CLOSE_SESSION
* DT bindings in a separate patch
* Assembly parts moved to arch/arm and arch/arm64 respectively, in a
separate patch
* Redefined/clarified the meaning of OPTEE_SMC_SHM_CACHED
* Removed CMA usage to limit the scope of the patch set
v3:
* Rebased on 4.1-rc3 (dma_buf_export() API change)
* A couple of small sparse fixes
* Documents bindings for OP-TEE driver
* Updated MAINTAINERS
v2:
* Replaced the stubbed OP-TEE driver with a real OP-TEE driver
* Removed most APIs not needed by OP-TEE in current state
* Update Documentation/ioctl/ioctl-number.txt with correct path to tee.h
* Rename tee_shm_pool_alloc_cma() to tee_shm_pool_alloc()
* Moved tee.h into include/uapi/linux/
* Redefined tee.h IOCTL macros to be directly based on _IOR and friends
* Removed version info on the API to user space, a data blob which
can contain an UUID is left for user space to be able to tell which
protocol to use in TEE_IOC_CMD
* Changed user space exposed structures to only have types with __ prefix
* Dropped THIS_MODULE from tee_fops
* Reworked how the driver is registered and ref counted:
- moved from using an embedded struct miscdevice to an embedded struct
device.
- uses an struct rw_semaphore as synchronization for driver detachment
- uses alloc/register pattern from TPM
Thanks,
Jens
Jens Wiklander (4):
dt/bindings: add bindings for optee
tee: generic TEE subsystem
tee: add OP-TEE driver
Documentation: tee subsystem and op-tee driver
Documentation/00-INDEX | 2 +
.../bindings/arm/firmware/linaro,optee-tz.txt | 31 +
.../devicetree/bindings/vendor-prefixes.txt | 1 +
Documentation/ioctl/ioctl-number.txt | 1 +
Documentation/tee.txt | 118 +++
MAINTAINERS | 13 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/tee/Kconfig | 18 +
drivers/tee/Makefile | 5 +
drivers/tee/optee/Kconfig | 7 +
drivers/tee/optee/Makefile | 5 +
drivers/tee/optee/call.c | 435 ++++++++++
drivers/tee/optee/core.c | 598 ++++++++++++++
drivers/tee/optee/optee_msg.h | 435 ++++++++++
drivers/tee/optee/optee_private.h | 185 +++++
drivers/tee/optee/optee_smc.h | 446 ++++++++++
drivers/tee/optee/rpc.c | 404 +++++++++
drivers/tee/optee/supp.c | 273 +++++++
drivers/tee/tee_core.c | 901 +++++++++++++++++++++
drivers/tee/tee_private.h | 129 +++
drivers/tee/tee_shm.c | 357 ++++++++
drivers/tee/tee_shm_pool.c | 158 ++++
include/linux/tee_drv.h | 278 +++++++
include/uapi/linux/tee.h | 403 +++++++++
25 files changed, 5206 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.txt
create mode 100644 Documentation/tee.txt
create mode 100644 drivers/tee/Kconfig
create mode 100644 drivers/tee/Makefile
create mode 100644 drivers/tee/optee/Kconfig
create mode 100644 drivers/tee/optee/Makefile
create mode 100644 drivers/tee/optee/call.c
create mode 100644 drivers/tee/optee/core.c
create mode 100644 drivers/tee/optee/optee_msg.h
create mode 100644 drivers/tee/optee/optee_private.h
create mode 100644 drivers/tee/optee/optee_smc.h
create mode 100644 drivers/tee/optee/rpc.c
create mode 100644 drivers/tee/optee/supp.c
create mode 100644 drivers/tee/tee_core.c
create mode 100644 drivers/tee/tee_private.h
create mode 100644 drivers/tee/tee_shm.c
create mode 100644 drivers/tee/tee_shm_pool.c
create mode 100644 include/linux/tee_drv.h
create mode 100644 include/uapi/linux/tee.h
--
1.9.1
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Leo Yan @ 2016-10-28 10:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <95e22336-0465-f1e1-71b8-548d0e6ee8b7@samsung.com>
On Fri, Oct 28, 2016 at 06:54:58PM +0900, Jaehoon Chung wrote:
[...]
> >>> Could you share the log? Is there any log about failure?
> >>
> >> Sure, please see below log:
> >
> > It's related with -EPROBE_DEFER..I'm not sure but if CONFIG_RESET_CONTROLLER is enabled, it's searching for reset controller.
> > Maybe hi6220 has handled the reset controller(?)...
> >
> > I'm checking devm_reset_control_xxx...It's possible to occur the other boards which enabled RESET_CONTROLLER..
>
> Could you check the below thing..
>
> /* find reset controller when exist */
> - pdata->rstc = devm_reset_control_get_optional(dev, NULL);
> + pdata->rstc = devm_reset_control_get_optional(dev, "dwmci-reset");
> if (IS_ERR(pdata->rstc)) {
> if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
> return ERR_PTR(-EPROBE_DEFER);
Confirmed with this fixing, the kernel can bootup successfully.
Thanks for this.
> To prevent the wrong controlling, how about adding "#reset-names" for dwmmc controller?
>
>
> Best Regards,
> Jaehoon Chung
^ permalink raw reply
* [PATCH 1/2] of, numa: Add function to disable of_node_to_nid().
From: Will Deacon @ 2016-10-28 10:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477431061-7258-2-git-send-email-ddaney.cavm@gmail.com>
On Tue, Oct 25, 2016 at 02:31:00PM -0700, David Daney wrote:
> From: David Daney <david.daney@cavium.com>
>
> On arm64 NUMA kernels we can pass "numa=off" on the command line to
> disable NUMA. A side effect of this is that kmalloc_node() calls to
> non-zero nodes will crash the system with an OOPS:
>
> [ 0.000000] [<fffffc00081bba84>] __alloc_pages_nodemask+0xa4/0xe68
> [ 0.000000] [<fffffc00082163a8>] new_slab+0xd0/0x57c
> [ 0.000000] [<fffffc000821879c>] ___slab_alloc+0x2e4/0x514
> [ 0.000000] [<fffffc000823882c>] __slab_alloc+0x48/0x58
> [ 0.000000] [<fffffc00082195a0>] __kmalloc_node+0xd0/0x2e0
> [ 0.000000] [<fffffc00081119b8>] __irq_domain_add+0x7c/0x164
> [ 0.000000] [<fffffc0008b75d30>] its_probe+0x784/0x81c
> [ 0.000000] [<fffffc0008b75e10>] its_init+0x48/0x1b0
> .
> .
> .
>
> This is caused by code like this in kernel/irq/irqdomain.c
>
> domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
> GFP_KERNEL, of_node_to_nid(of_node));
>
> When NUMA is disabled, the concept of a node is really undefined, so
> of_node_to_nid() should unconditionally return NUMA_NO_NODE.
>
> Add __of_force_no_numa() to allow of_node_to_nid() to be forced to
> return NUMA_NO_NODE.
>
> The follow on patch will call this new function from the arm64 numa
> code.
>
> Reported-by: Gilbert Netzer <noname@pdc.kth.se>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> drivers/of/of_numa.c | 15 +++++++++++++++
> include/linux/of.h | 2 ++
> 2 files changed, 17 insertions(+)
>
> diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c
> index f63d4b0d..2212299 100644
> --- a/drivers/of/of_numa.c
> +++ b/drivers/of/of_numa.c
> @@ -150,12 +150,27 @@ static int __init of_numa_parse_distance_map(void)
> return ret;
> }
>
> +static bool of_force_no_numa;
> +
> +void __of_force_no_numa(void)
> +{
> + of_force_no_numa = true;
> +}
> +
> int of_node_to_nid(struct device_node *device)
> {
> struct device_node *np;
> u32 nid;
> int r = -ENODATA;
>
> + /*
> + * If NUMA forced off, nodes are meaningless. Return
> + * NUMA_NO_NODE so that any node specific memory allocations
> + * can succeed from the default pool.
> + */
> + if (of_force_no_numa)
> + return NUMA_NO_NODE;
Why don't you just check if the nid you get back from the device is set in
numa_nodes_parsed and return NUMA_NO_NODE if not?
Will
^ permalink raw reply
* [PATCH 3/3] ARM: dts: sun9i: cubieboard4: Enable AP6330 WiFi
From: Chen-Yu Tsai @ 2016-10-28 10:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161028101154.7350-1-wens@csie.org>
The board has a Ampak AP6330 WiFi/BT/FM module. Inside it is a Broadcom
BCM4330 WiFi/BT/FM combo IC. The WiFi portion is connected to mmc1, with
the enabling pin connected to PL2. The AC100 RTC provides a low power
clock signal.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80-cubieboard4.dts | 32 +++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 439847acd41e..67b02fe7f11c 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -76,6 +76,14 @@
gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
};
};
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&ac100_rtc 1>;
+ clock-names = "ext_clock";
+ /* enables internal regulator and de-asserts reset */
+ reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 WL-PMU-EN */
+ };
};
&mmc0 {
@@ -88,6 +96,21 @@
status = "okay";
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>, <&wifi_en_pin_cubieboard4>;
+ vmmc-supply = <®_dldo1>;
+ vqmmc-supply = <®_cldo3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&mmc1_pins {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_8bit_pins>;
@@ -128,6 +151,15 @@
status = "okay";
};
+&r_pio {
+ wifi_en_pin_cubieboard4: wifi_en_pin at 0 {
+ allwinner,pins = "PL2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
&r_rsb {
status = "okay";
--
2.9.3
^ permalink raw reply related
* [PATCH 2/3] ARM: dts: sun9i: a80-optimus: Enable AP6330 WiFi
From: Chen-Yu Tsai @ 2016-10-28 10:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161028101154.7350-1-wens@csie.org>
The board has a Ampak AP6330 WiFi/BT/FM module. Inside it is a Broadcom
BCM4330 WiFi/BT/FM combo IC. The WiFi portion is connected to mmc1, with
the enabling pin connected to PL2. The AC100 RTC provides a low power
clock signal.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80-optimus.dts | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index ceb6ef15d669..7e036b2be762 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -105,6 +105,14 @@
enable-active-high;
gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
};
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&ac100_rtc 1>;
+ clock-names = "ext_clock";
+ /* enables internal regulator and de-asserts reset */
+ reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 WL-PMU-EN */
+ };
};
&ehci0 {
@@ -130,6 +138,21 @@
status = "okay";
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>, <&wifi_en_pin_optimus>;
+ vmmc-supply = <®_dldo1>;
+ vqmmc-supply = <®_cldo3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&mmc1_pins {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_8bit_pins>;
@@ -199,6 +222,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ wifi_en_pin_optimus: wifi_en_pin at 0 {
+ allwinner,pins = "PL2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
&r_rsb {
--
2.9.3
^ permalink raw reply related
* [PATCH 1/3] ARM: dts: sun9i: Add mmc1 pinmux setting
From: Chen-Yu Tsai @ 2016-10-28 10:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161028101154.7350-1-wens@csie.org>
On the A80, mmc1 is available on pingroup G. Designs mostly use this
to connect to an SDIO WiFi chip.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun9i-a80.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 3c5214cbe4e6..ab6a221027ef 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -700,6 +700,14 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ mmc1_pins: mmc1 {
+ allwinner,pins = "PG0", "PG1" ,"PG2", "PG3",
+ "PG4", "PG5";
+ allwinner,function = "mmc1";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc2_8bit_pins: mmc2_8bit {
allwinner,pins = "PC6", "PC7", "PC8", "PC9",
"PC10", "PC11", "PC12",
--
2.9.3
^ permalink raw reply related
* [PATCH 0/3] ARM: dts: sun9i: Enable SDIO-based WiFi
From: Chen-Yu Tsai @ 2016-10-28 10:11 UTC (permalink / raw)
To: linux-arm-kernel
Hi Maxime,
Now that we have support for both PMICs, we can turn on the
regulators needed for the onboard WiFi chips.
This is a fairly simple series. The WiFi chips themselves are
supported by the brcmfmac driver, but the user needs to get an
nvram.txt file and put it in their firmware directory, in
addition to the firmware file in linux-firmware. Otherwise we
just need to enable the mmc controller and supply the vmmc and
vqmmc regulators.
Regards
ChenYu
Chen-Yu Tsai (3):
ARM: dts: sun9i: Add mmc1 pinmux setting
ARM: dts: sun9i: a80-optimus: Enable AP6330 WiFi
ARM: dts: sun9i: cubieboard4: Enable AP6330 WiFi
arch/arm/boot/dts/sun9i-a80-cubieboard4.dts | 32 +++++++++++++++++++++++++++++
arch/arm/boot/dts/sun9i-a80-optimus.dts | 30 +++++++++++++++++++++++++++
arch/arm/boot/dts/sun9i-a80.dtsi | 8 ++++++++
3 files changed, 70 insertions(+)
--
2.9.3
^ permalink raw reply
* [PATCH] ARM: DTS: da850: Add DMA to SPI0
From: Sekhar Nori @ 2016-10-28 10:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477438368-16208-1-git-send-email-david@lechnology.com>
On Wednesday 26 October 2016 05:02 AM, David Lechner wrote:
> Add the bindings for DMA on SPI0
>
> Signed-off-by: David Lechner <david@lechnology.com>
Applied to v4.10/dt. small-case'd "DTS" in subject line while applying.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v7 0/4] da8xx USB PHY platform devices and clocks
From: Sekhar Nori @ 2016-10-28 9:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477527498-21930-1-git-send-email-david@lechnology.com>
On Thursday 27 October 2016 05:48 AM, David Lechner wrote:
> This series depends on [v3] ARM: davinci: da8xx: Fix some redefined symbol
> warnings <https://patchwork.kernel.org/patch/9397005/> being applied first.
>
> v7 changes:
> * Dropped patches that have been accepted into linux-davinci already
> * New patch for adding device names to clock lookup tables
> * Picked up related patch from Axel Haslam for registering USB PHY clocks on
> device tree boards and added error checking to to that patch
> * Rebased on latest linux-davinci + linux-next
> * Added devices instead of NULL in clk_get() where appropriate usb-da8xx.c
> * Re-ordered patches so that they apply/build cleanly
The series looks good to me now. Since this is considerable change from
previous version, I will wait a while to see if others have any comments
before applying this.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Jaehoon Chung @ 2016-10-28 9:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <24930ad4-313f-a4f0-c89a-770238863816@samsung.com>
Hi,
On 10/28/2016 06:43 PM, Jaehoon Chung wrote:
> Hi,
>
> On 10/28/2016 04:38 PM, Leo Yan wrote:
>> On Fri, Oct 28, 2016 at 04:33:41PM +0900, Jaehoon Chung wrote:
>>
>> [...]
>>
>>>>>> Guodong: Is there any bootloader dependency on that change?
>>>>>
>>>>> FYI, I use firmwares available in AOSP
>>>>
>>>> I tried latest firmware [1], still cannot boot up until revert the
>>>> patch "arm64: dts: hi6220: add resets property into dwmmc nodes".
>>>
>>> Could you share the log? Is there any log about failure?
>>
>> Sure, please see below log:
>
> It's related with -EPROBE_DEFER..I'm not sure but if CONFIG_RESET_CONTROLLER is enabled, it's searching for reset controller.
> Maybe hi6220 has handled the reset controller(?)...
>
> I'm checking devm_reset_control_xxx...It's possible to occur the other boards which enabled RESET_CONTROLLER..
Could you check the below thing..
/* find reset controller when exist */
- pdata->rstc = devm_reset_control_get_optional(dev, NULL);
+ pdata->rstc = devm_reset_control_get_optional(dev, "dwmci-reset");
if (IS_ERR(pdata->rstc)) {
if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
To prevent the wrong controlling, how about adding "#reset-names" for dwmmc controller?
Best Regards,
Jaehoon Chung
>
> Best Regards,
> Jaehoon Chung
>
>>
>> EFI stub: Booting Linux Kernel...
>> EFI stub: Using DTB from configuration table
>> EFI stub: Exiting boot services and installing virtual address map...
>> [ 0.000000] Booting Linux on physical CPU 0x0
>> [ 0.000000] Linux version 4.9.0-rc1-00251-g323792f (leoy at leoy-linaro) (gcc version 4.9.2 20140904 (prerelease) (crosstool-NG linaro-1.13.1-4.9-2014.09 - Linaro GCC 4.9-2014.09) ) #589 SMP PREEMPT Fri Oct 28 15:35:15 CST 2016
>> [ 0.000000] Boot CPU: AArch64 Processor [410fd033]
>> [ 0.000000] efi: Getting EFI parameters from FDT:
>> [ 0.000000] efi: EFI v2.50 by hikey EFI Oct 26 2016 15:14:29
>> [ 0.000000] efi: PROP=0x3d8297d8
>> [ 0.000000] Reserved memory: created CMA memory pool at 0x000000002d000000, size 128 MiB
>> [ 0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
>> [ 0.000000] psci: probing for conduit method from DT.
>> [ 0.000000] psci: PSCIv1.0 detected in firmware.
>> [ 0.000000] psci: Using standard PSCI v0.2 function IDs
>> [ 0.000000] psci: MIGRATE_INFO_TYPE not supported.
>> [ 0.000000] percpu: Embedded 21 pages/cpu @ffff80003df10000 s48000 r8192 d29824 u86016
>> [ 0.000000] Detected VIPT I-cache on CPU0
>> [ 0.000000] CPU features: enabling workaround for ARM erratum 845719
>> [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 249229
>> [ 0.000000] Kernel command line: BOOT_IMAGE=(hd0,gpt6)/Image console=tty0 console=ttyAMA3,115200 root=/dev/disk/by-partlabel/system rootwait rw efi=noruntime
>> [ 0.000000] log_buf_len individual max cpu contribution: 4096 bytes
>> [ 0.000000] log_buf_len total cpu_extra contributions: 28672 bytes
>> [ 0.000000] log_buf_len min size: 16384 bytes
>> [ 0.000000] log_buf_len: 65536 bytes
>> [ 0.000000] early log buf free: 14468(88%)
>> [ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
>> [ 0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
>> [ 0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
>> [ 0.000000] Memory: 841572K/1012788K available (8316K kernel code, 860K rwdata, 3668K rodata, 1024K init, 283K bss, 40144K reserved, 131072K cma-reserved)
>> [ 0.000000] Virtual kernel memory layout:
>> [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB)
>> [ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB)
>> [ 0.000000] .text : 0xffff000008080000 - 0xffff0000088a0000 ( 8320 KB)
>> [ 0.000000] .rodata : 0xffff0000088a0000 - 0xffff000008c40000 ( 3712 KB)
>> [ 0.000000] .init : 0xffff000008c40000 - 0xffff000008d40000 ( 1024 KB)
>> [ 0.000000] .data : 0xffff000008d40000 - 0xffff000008e17200 ( 861 KB)
>> [ 0.000000] .bss : 0xffff000008e17200 - 0xffff000008e5e0c0 ( 284 KB)
>> [ 0.000000] fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB)
>> [ 0.000000] PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB)
>> [ 0.000000] vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum)
>> [ 0.000000] 0xffff7e0000000000 - 0xffff7e0000f80000 ( 15 MB actual)
>> [ 0.000000] memory : 0xffff800000000000 - 0xffff80003e000000 ( 992 MB)
>> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
>> [ 0.000000] Preemptible hierarchical RCU implementation.
>> [ 0.000000] Build-time adjustment of leaf fanout to 64.
>> [ 0.000000] RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=8.
>> [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=8
>> [ 0.000000] NR_IRQS:64 nr_irqs:64 0
>> [ 0.000000] GIC: Using split EOI/Deactivate mode
>> [ 0.000000] arm_arch_timer: Architected cp15 timer(s) running at 1.20MHz (phys).
>> [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x11b661f8e, max_idle_ns: 1763180809113 ns
>> [ 0.000004] sched_clock: 56 bits at 1200kHz, resolution 833ns, wraps every 4398046510838ns
>> [ 0.000101] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 99544814920 ns
>> [ 0.000108] sched_clock: 32 bits at 19MHz, resolution 52ns, wraps every 111848106981ns
>> [ 0.000495] Console: colour dummy device 80x25
>> [ 0.001193] console [tty0] enabled
>> [ 0.001224] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.40 BogoMIPS (lpj=4800)
>> [ 0.001253] pid_max: default: 32768 minimum: 301
>> [ 0.001331] Security Framework initialized
>> [ 0.001373] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
>> [ 0.001392] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
>> [ 0.002258] ASID allocator initialised with 65536 entries
>> [ 0.032726] EFI runtime services will be disabled.
>> [ 0.080274] Detected VIPT I-cache on CPU1
>> [ 0.080323] CPU1: Booted secondary processor [410fd033]
>> [ 0.112299] Detected VIPT I-cache on CPU2
>> [ 0.112321] CPU2: Booted secondary processor [410fd033]
>> [ 0.144348] Detected VIPT I-cache on CPU3
>> [ 0.144369] CPU3: Booted secondary processor [410fd033]
>> [ 0.176488] Detected VIPT I-cache on CPU4
>> [ 0.176529] CPU4: Booted secondary processor [410fd033]
>> [ 0.208479] Detected VIPT I-cache on CPU5
>> [ 0.208501] CPU5: Booted secondary processor [410fd033]
>> [ 0.240546] Detected VIPT I-cache on CPU6
>> [ 0.240568] CPU6: Booted secondary processor [410fd033]
>> [ 0.272610] Detected VIPT I-cache on CPU7
>> [ 0.272632] CPU7: Booted secondary processor [410fd033]
>> [ 0.272708] Brought up 8 CPUs
>> [ 0.272887] SMP: Total of 8 processors activated.
>> [ 0.272904] CPU features: detected feature: 32-bit EL0 Support
>> [ 0.272975] CPU: All CPU(s) started at EL2
>> [ 0.273028] alternatives: patching kernel code
>> [ 0.273645] devtmpfs: initialized
>> [ 0.278919] DMI not present or invalid.
>> [ 0.279161] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
>> [ 0.282522] pinctrl core: initialized pinctrl subsystem
>> [ 0.283636] NET: Registered protocol family 16
>> [ 0.300541] cpuidle: using governor menu
>> [ 0.301073] vdso: 2 pages (1 code @ ffff0000088a7000, 1 data @ ffff000008d44000)
>> [ 0.301106] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
>> [ 0.301863] DMA: preallocated 256 KiB pool for atomic allocations
>> [ 0.302088] Serial: AMBA PL011 UART driver
>> [ 0.303683] f8015000.uart: ttyAMA0 at MMIO 0xf8015000 (irq = 7, base_baud = 0) is a PL011 rev2
>> [ 0.304121] uart-pl011 f7111000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart1_pmx_func, deferring probe
>> [ 0.304340] uart-pl011 f7112000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart2_pmx_func, deferring probe
>> [ 0.304580] uart-pl011 f7113000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart3_pmx_func, deferring probe
>> [ 0.310373] hi6220-mbox f7510000.mailbox: Mailbox enabled
>> [ 0.341400] HugeTLB registered 2 MB page size, pre-allocated 0 pages
>> [ 0.342257] ACPI: Interpreter disabled.
>> [ 0.342953] vgaarb: loaded
>> [ 0.343177] SCSI subsystem initialized
>> [ 0.343450] ssp-pl022 f7106000.spi: could not find pctldev for node /soc/pinmux at f7010000/spi0_pmx_func, deferring probe
>> [ 0.343955] usbcore: registered new interface driver usbfs
>> [ 0.344042] usbcore: registered new interface driver hub
>> [ 0.344177] usbcore: registered new device driver usb
>> [ 0.344452] i2c_designware f7100000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c0_pmx_func, deferring probe
>> [ 0.344494] i2c_designware f7101000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c1_pmx_func, deferring probe
>> [ 0.344535] i2c_designware f7102000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c2_pmx_func, deferring probe
>> [ 0.344915] pps_core: LinuxPPS API ver. 1 registered
>> [ 0.344931] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
>> [ 0.345003] PTP clock support registered
>> [ 0.345325] dmi: Firmware registration failed.
>> [ 0.345408] Registered efivars operations
>> [ 0.345580] Advanced Linux Sound Architecture Driver Initialized.
>> [ 0.346449] clocksource: Switched to clocksource arch_sys_counter
>> [ 0.346617] VFS: Disk quotas dquot_6.6.0
>> [ 0.346670] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
>> [ 0.346935] pnp: PnP ACPI: disabled
>> [ 0.355325] NET: Registered protocol family 2
>> [ 0.355797] TCP established hash table entries: 8192 (order: 4, 65536 bytes)
>> [ 0.355885] TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
>> [ 0.356026] TCP: Hash tables configured (established 8192 bind 8192)
>> [ 0.356085] UDP hash table entries: 512 (order: 2, 16384 bytes)
>> [ 0.356120] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
>> [ 0.356255] NET: Registered protocol family 1
>> [ 0.356569] RPC: Registered named UNIX socket transport module.
>> [ 0.356585] RPC: Registered udp transport module.
>> [ 0.356599] RPC: Registered tcp transport module.
>> [ 0.356613] RPC: Registered tcp NFSv4.1 backchannel transport module.
>> [ 0.356791] Unpacking initramfs...
>> [ 0.497134] Freeing initrd memory: 3576K (ffff8000372d5000 - ffff800037653000)
>> [ 0.497725] kvm [1]: 8-bit VMID
>> [ 0.497744] kvm [1]: IDMAP page: 890000
>> [ 0.497758] kvm [1]: HYP VA range: 800000000000:ffffffffffff
>> [ 0.498691] kvm [1]: Hyp mode initialized successfully
>> [ 0.498741] kvm [1]: vgic-v2 at f6804000
>> [ 0.498936] kvm [1]: vgic interrupt IRQ1
>> [ 0.498978] kvm [1]: virtual timer IRQ4
>> [ 0.501267] futex hash table entries: 2048 (order: 6, 262144 bytes)
>> [ 0.501394] audit: initializing netlink subsys (disabled)
>> [ 0.501462] audit: type=2000 audit(0.495:1): initialized
>> [ 0.501845] workingset: timestamp_bits=46 max_order=18 bucket_order=0
>> [ 0.508960] squashfs: version 4.0 (2009/01/31) Phillip Lougher
>> [ 0.509596] NFS: Registering the id_resolver key type
>> [ 0.509632] Key type id_resolver registered
>> [ 0.509645] Key type id_legacy registered
>> [ 0.509665] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
>> [ 0.509833] 9p: Installing v9fs 9p2000 file system support
>> [ 0.512208] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 247)
>> [ 0.512235] io scheduler noop registered
>> [ 0.512349] io scheduler cfq registered (default)
>> [ 0.513271] libphy: mdio_driver_register: phy-bcm-ns2-pci
>> [ 0.514198] pinctrl-single f7010000.pinmux: 159 pins at pa ffff000008e81000 size 636
>> [ 0.514612] pinctrl-single f7010800.pinmux: 163 pins at pa ffff000008e83800 size 652
>> [ 0.514770] pinctrl-single f8001800.pinmux: 30 pins at pa ffff000008e85800 size 120
>> [ 0.515809] pl061_gpio f8011000.gpio: PL061 GPIO chip @0x00000000f8011000 registered
>> [ 0.516214] pl061_gpio f8012000.gpio: PL061 GPIO chip @0x00000000f8012000 registered
>> [ 0.516610] pl061_gpio f8013000.gpio: PL061 GPIO chip @0x00000000f8013000 registered
>> [ 0.516687] gpio gpiochip3: gpio-line-names specifies 9 line names but there are 8 lines on the chip
>> [ 0.517038] pl061_gpio f8014000.gpio: PL061 GPIO chip @0x00000000f8014000 registered
>> [ 0.517416] pl061_gpio f7020000.gpio: PL061 GPIO chip @0x00000000f7020000 registered
>> [ 0.517796] pl061_gpio f7021000.gpio: PL061 GPIO chip @0x00000000f7021000 registered
>> [ 0.518172] pl061_gpio f7022000.gpio: PL061 GPIO chip @0x00000000f7022000 registered
>> [ 0.518577] pl061_gpio f7023000.gpio: PL061 GPIO chip @0x00000000f7023000 registered
>> [ 0.518658] gpio gpiochip8: gpio-line-names specifies 9 line names but there are 8 lines on the chip
>> [ 0.518999] pl061_gpio f7024000.gpio: PL061 GPIO chip @0x00000000f7024000 registered
>> [ 0.519385] pl061_gpio f7025000.gpio: PL061 GPIO chip @0x00000000f7025000 registered
>> [ 0.519774] pl061_gpio f7026000.gpio: PL061 GPIO chip @0x00000000f7026000 registered
>> [ 0.520162] pl061_gpio f7027000.gpio: PL061 GPIO chip @0x00000000f7027000 registered
>> [ 0.520550] pl061_gpio f7028000.gpio: PL061 GPIO chip @0x00000000f7028000 registered
>> [ 0.520939] pl061_gpio f7029000.gpio: PL061 GPIO chip @0x00000000f7029000 registered
>> [ 0.521324] pl061_gpio f702a000.gpio: PL061 GPIO chip @0x00000000f702a000 registered
>> [ 0.521719] pl061_gpio f702b000.gpio: PL061 GPIO chip @0x00000000f702b000 registered
>> [ 0.522107] pl061_gpio f702c000.gpio: PL061 GPIO chip @0x00000000f702c000 registered
>> [ 0.522505] pl061_gpio f702d000.gpio: PL061 GPIO chip @0x00000000f702d000 registered
>> [ 0.522884] pl061_gpio f702e000.gpio: PL061 GPIO chip @0x00000000f702e000 registered
>> [ 0.523275] pl061_gpio f702f000.gpio: PL061 GPIO chip @0x00000000f702f000 registered
>> [ 0.526086] xenfs: not registering filesystem on non-xen platform
>> [ 0.528934] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
>> [ 0.530124] SuperH (H)SCI(F) driver initialized
>> [ 0.530364] msm_serial: driver initialized
>> [ 0.536344] loop: module loaded
>> [ 0.539526] hisi_sas: driver version v1.6
>> [ 0.541976] libphy: Fixed MDIO Bus: probed
>> [ 0.542702] tun: Universal TUN/TAP device driver, 1.6
>> [ 0.542719] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
>> [ 0.543688] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
>> [ 0.543707] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
>> [ 0.543804] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k
>> [ 0.543821] igb: Copyright (c) 2007-2014 Intel Corporation.
>> [ 0.543906] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.4.0-k
>> [ 0.543930] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
>> [ 0.544018] sky2: driver version 1.30
>> [ 0.544551] VFIO - User Level meta-driver version: 0.3
>> [ 0.546560] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
>> [ 0.546590] ehci-pci: EHCI PCI platform driver
>> [ 0.546638] ehci-platform: EHCI generic platform driver
>> [ 0.546730] ehci-exynos: EHCI EXYNOS driver
>> [ 0.546802] ehci-msm: Qualcomm On-Chip EHCI Host Controller
>> [ 0.546866] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
>> [ 0.546900] ohci-pci: OHCI PCI platform driver
>> [ 0.546952] ohci-platform: OHCI generic platform driver
>> [ 0.547024] ohci-exynos: OHCI EXYNOS driver
>> [ 0.547324] usbcore: registered new interface driver usb-storage
>> [ 0.547863] file system registered
>> [ 0.548183] mousedev: PS/2 mouse device common for all mice
>> [ 0.548621] input: HISI 65xx PowerOn Key as /devices/platform/f8000000.pmic/hi65xx-powerkey.0.auto/input/input0
>> [ 0.549253] rtc-pl031 f8003000.rtc: rtc core: registered pl031 as rtc0
>> [ 0.549459] rtc-pl031 f8004000.rtc: rtc core: registered pl031 as rtc1
>> [ 0.549796] i2c /dev entries driver
>> [ 0.552183] sdhci: Secure Digital Host Controller Interface driver
>> [ 0.552207] sdhci: Copyright(c) Pierre Ossman
>> [ 0.552403] Synopsys Designware Multimedia Card Interface Driver
>> [ 0.553405] sdhci-pltfm: SDHCI platform and OF driver helper
>> [ 0.554851] ledtrig-cpu: registered to indicate activity on CPUs
>> [ 0.555695] usbcore: registered new interface driver usbhid
>> [ 0.555717] usbhid: USB HID core driver
>> [ 0.557233] NET: Registered protocol family 17
>> [ 0.557320] 9pnet: Installing 9P2000 support
>> [ 0.557383] Key type dns_resolver registered
>> [ 0.557996] registered taskstats version 1
>> [ 0.561690] f7111000.uart: ttyAMA1 at MMIO 0xf7111000 (irq = 8, base_baud = 0) is a PL011 rev2
>> [ 0.562226] f7112000.uart: ttyAMA2 at MMIO 0xf7112000 (irq = 9, base_baud = 0) is a PL011 rev2
>> [ 0.562553] f7113000.uart: ttyAMA3 at MMIO 0xf7113000 (irq = 10, base_baud = 0) is a PL011 rev2
>> [ 1.916968] console [ttyAMA3] enabled
>> [ 1.922080] ssp-pl022 f7106000.spi: ARM PL022 driver, device ID: 0x00041022
>> [ 1.929144] ssp-pl022 f7106000.spi: mapped registers from 0x00000000f7106000 to ffff000008f03000
>> [ 1.938007] ssp-pl022 f7106000.spi: Failed to work in dma mode, work without dma!
>> [ 1.949535] f72c0000.usb supply vusb_d not found, using dummy regulator
>> [ 1.956256] f72c0000.usb supply vusb_a not found, using dummy regulator
>> [ 2.344873] dwc2 f72c0000.usb: EPs: 16, dedicated fifos, 1920 entries in SPRAM
>> [ 2.353154] dwc2 f72c0000.usb: DWC OTG Controller
>> [ 2.357891] dwc2 f72c0000.usb: new USB bus registered, assigned bus number 1
>> [ 2.364979] dwc2 f72c0000.usb: irq 38, io mem 0x00000000
>> [ 2.371082] hub 1-0:1.0: USB hub found
>> [ 2.374866] hub 1-0:1.0: 1 port detected
>> [ 2.382071] rtc-pl031 f8003000.rtc: setting system clock to 1970-01-01 00:00:19 UTC (19)
>> [ 2.390486] LDO2_2V8: disabling
>> [ 2.393639] LDO7_SDIO: disabling
>> [ 2.396900] LDO10_2V85: disabling
>> [ 2.400234] LDO13_1V8: disabling
>> [ 2.403476] LDO14_2V8: disabling
>> [ 2.406721] LDO17_2V5: disabling
>> [ 2.409956] LDO19_3V0: disabling
>> [ 2.413199] wlan-en-regulator: disabling
>> [ 2.417135] ALSA device list:
>> [ 2.420109] No soundcards found.
>> [ 2.423712] uart-pl011 f7113000.uart: no DMA platform data
>> [ 2.429585] Freeing unused kernel memory: 1024K (ffff800000c40000 - ffff800000d40000)
>> Loading, please wait...
>> starting version 228
>> [ 2.479981] random: systemd-udevd: uninitialized urandom read (16 bytes read)
>> [ 2.483570] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.483680] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.485404] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.485631] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.485859] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.486098] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.486305] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.486729] random: udevadm: uninitialized urandom read (16 bytes read)
>> [ 2.486951] random: udevadm: uninitialized urandom read (16 bytes read)
>> Begin: Loading essential drivers ... done.
>> Begin: Running /scripts/init-premount ... done.
>> Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
>> Begin: Running /scripts/local-premount ... modprobe: can't change directory to '4.9.0-rc1-00251-g323792f': No such file or directory
>> done.
>> Begin: Waiting for root file system ... Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>> Begin: Running /scripts/local-block ... done.
>>
>> Thanks,
>> Leo Yan
>>
>>
>>
>
^ permalink raw reply
* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Uwe Kleine-König @ 2016-10-28 9:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027231331.gngekbg22wfvnolr@piout.net>
On Fri, Oct 28, 2016 at 01:13:31AM +0200, Alexandre Belloni wrote:
> On 27/10/2016 at 20:02:29 +0200, Uwe Kleine-K?nig wrote :
> > Hello Richard,
> >
> > On Thu, Oct 27, 2016 at 06:04:06PM +0200, Richard Genoud wrote:
> > > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> > > index fd8aa1f4ba78..168b10cad47b 100644
> > > --- a/drivers/tty/serial/atmel_serial.c
> > > +++ b/drivers/tty/serial/atmel_serial.c
> > > @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> > > mode |= ATMEL_US_USMODE_RS485;
> > > } else if (termios->c_cflag & CRTSCTS) {
> > > /* RS232 with hardware handshake (RTS/CTS) */
> > > - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
> > > - dev_info(port->dev, "not enabling hardware flow control because DMA is used");
> > > - termios->c_cflag &= ~CRTSCTS;
> > > - } else {
> > > + if (atmel_use_fifo(port) &&
> > > + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
> > > + /*
> > > + * with ATMEL_US_USMODE_HWHS set, the controller will
> > > + * be able to drive the RTS pin high/low when the RX
> > > + * FIFO is above RXFTHRES/below RXFTHRES2.
> > > + * It will also disable the transmitter when the CTS
> > > + * pin is high.
> > > + * This mode is not activated if CTS pin is a GPIO
> > > + * because in this case, the transmitter is always
> > > + * disabled (there must be an internal pull-up
> > > + * responsible for this behaviour).
> > > + * If the RTS pin is a GPIO, the controller won't be
> > > + * able to drive it according to the FIFO thresholds,
> > > + * but it will be handled by the driver.
> > > + */
> > > mode |= ATMEL_US_USMODE_HWHS;
> >
> > You use
> >
> > !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)
> >
> > as indicator that the cts mode of the respective pin is used. Is this
> > reliable? (It's not if there are machines that don't use CTS, neither as
> > gpio nor using the hardware function.) Maybe this needs a dt property to
> > indicate that there is no (hw)handshaking available?
> >
>
> We had a call today were we agreed that this should be added in a future
> patch. Let's fix the regression for now.
A machine without CTS (neither gpio nor hw function) used to work fine
before the breaking commit, right? So this case is part of the
regression and needs a fix?
Anyhow, this probably shouldn't stop the commit entering mainline
because there are probably very few such machines (if any).
So:
Acked-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH] ARM: davinci: Add full regulator constraints for non-DT boot
From: Sekhar Nori @ 2016-10-28 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161026194155.14304-1-ahaslam@baylibre.com>
On Thursday 27 October 2016 01:11 AM, ahaslam at baylibre.com wrote:
> From: Axel Haslam <ahaslam@baylibre.com>
>
> The phy framework requests an optional "phy" regulator. If it does
> not find one, it returns -EPROBE_DEFER. In the case of non-DT boot
> for the omap138-lcdk board, this would prevent the usb11 phy to probe
> correctly and ohci would not enumerate.
>
> By calling "regulator_has_full_constraints", An error would be returned
> instead of DEFER for the regulator, and the probe of the phy driver can
> continue normally without a regulator.
>
> Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Applied to v4.10/soc branch.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Jaehoon Chung @ 2016-10-28 9:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161028073830.GC17266@leoy-linaro>
Hi,
On 10/28/2016 04:38 PM, Leo Yan wrote:
> On Fri, Oct 28, 2016 at 04:33:41PM +0900, Jaehoon Chung wrote:
>
> [...]
>
>>>>> Guodong: Is there any bootloader dependency on that change?
>>>>
>>>> FYI, I use firmwares available in AOSP
>>>
>>> I tried latest firmware [1], still cannot boot up until revert the
>>> patch "arm64: dts: hi6220: add resets property into dwmmc nodes".
>>
>> Could you share the log? Is there any log about failure?
>
> Sure, please see below log:
It's related with -EPROBE_DEFER..I'm not sure but if CONFIG_RESET_CONTROLLER is enabled, it's searching for reset controller.
Maybe hi6220 has handled the reset controller(?)...
I'm checking devm_reset_control_xxx...It's possible to occur the other boards which enabled RESET_CONTROLLER..
Best Regards,
Jaehoon Chung
>
> EFI stub: Booting Linux Kernel...
> EFI stub: Using DTB from configuration table
> EFI stub: Exiting boot services and installing virtual address map...
> [ 0.000000] Booting Linux on physical CPU 0x0
> [ 0.000000] Linux version 4.9.0-rc1-00251-g323792f (leoy at leoy-linaro) (gcc version 4.9.2 20140904 (prerelease) (crosstool-NG linaro-1.13.1-4.9-2014.09 - Linaro GCC 4.9-2014.09) ) #589 SMP PREEMPT Fri Oct 28 15:35:15 CST 2016
> [ 0.000000] Boot CPU: AArch64 Processor [410fd033]
> [ 0.000000] efi: Getting EFI parameters from FDT:
> [ 0.000000] efi: EFI v2.50 by hikey EFI Oct 26 2016 15:14:29
> [ 0.000000] efi: PROP=0x3d8297d8
> [ 0.000000] Reserved memory: created CMA memory pool at 0x000000002d000000, size 128 MiB
> [ 0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
> [ 0.000000] psci: probing for conduit method from DT.
> [ 0.000000] psci: PSCIv1.0 detected in firmware.
> [ 0.000000] psci: Using standard PSCI v0.2 function IDs
> [ 0.000000] psci: MIGRATE_INFO_TYPE not supported.
> [ 0.000000] percpu: Embedded 21 pages/cpu @ffff80003df10000 s48000 r8192 d29824 u86016
> [ 0.000000] Detected VIPT I-cache on CPU0
> [ 0.000000] CPU features: enabling workaround for ARM erratum 845719
> [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 249229
> [ 0.000000] Kernel command line: BOOT_IMAGE=(hd0,gpt6)/Image console=tty0 console=ttyAMA3,115200 root=/dev/disk/by-partlabel/system rootwait rw efi=noruntime
> [ 0.000000] log_buf_len individual max cpu contribution: 4096 bytes
> [ 0.000000] log_buf_len total cpu_extra contributions: 28672 bytes
> [ 0.000000] log_buf_len min size: 16384 bytes
> [ 0.000000] log_buf_len: 65536 bytes
> [ 0.000000] early log buf free: 14468(88%)
> [ 0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
> [ 0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
> [ 0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
> [ 0.000000] Memory: 841572K/1012788K available (8316K kernel code, 860K rwdata, 3668K rodata, 1024K init, 283K bss, 40144K reserved, 131072K cma-reserved)
> [ 0.000000] Virtual kernel memory layout:
> [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000 ( 128 MB)
> [ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000 (129022 GB)
> [ 0.000000] .text : 0xffff000008080000 - 0xffff0000088a0000 ( 8320 KB)
> [ 0.000000] .rodata : 0xffff0000088a0000 - 0xffff000008c40000 ( 3712 KB)
> [ 0.000000] .init : 0xffff000008c40000 - 0xffff000008d40000 ( 1024 KB)
> [ 0.000000] .data : 0xffff000008d40000 - 0xffff000008e17200 ( 861 KB)
> [ 0.000000] .bss : 0xffff000008e17200 - 0xffff000008e5e0c0 ( 284 KB)
> [ 0.000000] fixed : 0xffff7dfffe7fd000 - 0xffff7dfffec00000 ( 4108 KB)
> [ 0.000000] PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000 ( 16 MB)
> [ 0.000000] vmemmap : 0xffff7e0000000000 - 0xffff800000000000 ( 2048 GB maximum)
> [ 0.000000] 0xffff7e0000000000 - 0xffff7e0000f80000 ( 15 MB actual)
> [ 0.000000] memory : 0xffff800000000000 - 0xffff80003e000000 ( 992 MB)
> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
> [ 0.000000] Preemptible hierarchical RCU implementation.
> [ 0.000000] Build-time adjustment of leaf fanout to 64.
> [ 0.000000] RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=8.
> [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=8
> [ 0.000000] NR_IRQS:64 nr_irqs:64 0
> [ 0.000000] GIC: Using split EOI/Deactivate mode
> [ 0.000000] arm_arch_timer: Architected cp15 timer(s) running at 1.20MHz (phys).
> [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x11b661f8e, max_idle_ns: 1763180809113 ns
> [ 0.000004] sched_clock: 56 bits at 1200kHz, resolution 833ns, wraps every 4398046510838ns
> [ 0.000101] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 99544814920 ns
> [ 0.000108] sched_clock: 32 bits at 19MHz, resolution 52ns, wraps every 111848106981ns
> [ 0.000495] Console: colour dummy device 80x25
> [ 0.001193] console [tty0] enabled
> [ 0.001224] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.40 BogoMIPS (lpj=4800)
> [ 0.001253] pid_max: default: 32768 minimum: 301
> [ 0.001331] Security Framework initialized
> [ 0.001373] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
> [ 0.001392] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
> [ 0.002258] ASID allocator initialised with 65536 entries
> [ 0.032726] EFI runtime services will be disabled.
> [ 0.080274] Detected VIPT I-cache on CPU1
> [ 0.080323] CPU1: Booted secondary processor [410fd033]
> [ 0.112299] Detected VIPT I-cache on CPU2
> [ 0.112321] CPU2: Booted secondary processor [410fd033]
> [ 0.144348] Detected VIPT I-cache on CPU3
> [ 0.144369] CPU3: Booted secondary processor [410fd033]
> [ 0.176488] Detected VIPT I-cache on CPU4
> [ 0.176529] CPU4: Booted secondary processor [410fd033]
> [ 0.208479] Detected VIPT I-cache on CPU5
> [ 0.208501] CPU5: Booted secondary processor [410fd033]
> [ 0.240546] Detected VIPT I-cache on CPU6
> [ 0.240568] CPU6: Booted secondary processor [410fd033]
> [ 0.272610] Detected VIPT I-cache on CPU7
> [ 0.272632] CPU7: Booted secondary processor [410fd033]
> [ 0.272708] Brought up 8 CPUs
> [ 0.272887] SMP: Total of 8 processors activated.
> [ 0.272904] CPU features: detected feature: 32-bit EL0 Support
> [ 0.272975] CPU: All CPU(s) started at EL2
> [ 0.273028] alternatives: patching kernel code
> [ 0.273645] devtmpfs: initialized
> [ 0.278919] DMI not present or invalid.
> [ 0.279161] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
> [ 0.282522] pinctrl core: initialized pinctrl subsystem
> [ 0.283636] NET: Registered protocol family 16
> [ 0.300541] cpuidle: using governor menu
> [ 0.301073] vdso: 2 pages (1 code @ ffff0000088a7000, 1 data @ ffff000008d44000)
> [ 0.301106] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
> [ 0.301863] DMA: preallocated 256 KiB pool for atomic allocations
> [ 0.302088] Serial: AMBA PL011 UART driver
> [ 0.303683] f8015000.uart: ttyAMA0 at MMIO 0xf8015000 (irq = 7, base_baud = 0) is a PL011 rev2
> [ 0.304121] uart-pl011 f7111000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart1_pmx_func, deferring probe
> [ 0.304340] uart-pl011 f7112000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart2_pmx_func, deferring probe
> [ 0.304580] uart-pl011 f7113000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart3_pmx_func, deferring probe
> [ 0.310373] hi6220-mbox f7510000.mailbox: Mailbox enabled
> [ 0.341400] HugeTLB registered 2 MB page size, pre-allocated 0 pages
> [ 0.342257] ACPI: Interpreter disabled.
> [ 0.342953] vgaarb: loaded
> [ 0.343177] SCSI subsystem initialized
> [ 0.343450] ssp-pl022 f7106000.spi: could not find pctldev for node /soc/pinmux at f7010000/spi0_pmx_func, deferring probe
> [ 0.343955] usbcore: registered new interface driver usbfs
> [ 0.344042] usbcore: registered new interface driver hub
> [ 0.344177] usbcore: registered new device driver usb
> [ 0.344452] i2c_designware f7100000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c0_pmx_func, deferring probe
> [ 0.344494] i2c_designware f7101000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c1_pmx_func, deferring probe
> [ 0.344535] i2c_designware f7102000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c2_pmx_func, deferring probe
> [ 0.344915] pps_core: LinuxPPS API ver. 1 registered
> [ 0.344931] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
> [ 0.345003] PTP clock support registered
> [ 0.345325] dmi: Firmware registration failed.
> [ 0.345408] Registered efivars operations
> [ 0.345580] Advanced Linux Sound Architecture Driver Initialized.
> [ 0.346449] clocksource: Switched to clocksource arch_sys_counter
> [ 0.346617] VFS: Disk quotas dquot_6.6.0
> [ 0.346670] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
> [ 0.346935] pnp: PnP ACPI: disabled
> [ 0.355325] NET: Registered protocol family 2
> [ 0.355797] TCP established hash table entries: 8192 (order: 4, 65536 bytes)
> [ 0.355885] TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
> [ 0.356026] TCP: Hash tables configured (established 8192 bind 8192)
> [ 0.356085] UDP hash table entries: 512 (order: 2, 16384 bytes)
> [ 0.356120] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
> [ 0.356255] NET: Registered protocol family 1
> [ 0.356569] RPC: Registered named UNIX socket transport module.
> [ 0.356585] RPC: Registered udp transport module.
> [ 0.356599] RPC: Registered tcp transport module.
> [ 0.356613] RPC: Registered tcp NFSv4.1 backchannel transport module.
> [ 0.356791] Unpacking initramfs...
> [ 0.497134] Freeing initrd memory: 3576K (ffff8000372d5000 - ffff800037653000)
> [ 0.497725] kvm [1]: 8-bit VMID
> [ 0.497744] kvm [1]: IDMAP page: 890000
> [ 0.497758] kvm [1]: HYP VA range: 800000000000:ffffffffffff
> [ 0.498691] kvm [1]: Hyp mode initialized successfully
> [ 0.498741] kvm [1]: vgic-v2 at f6804000
> [ 0.498936] kvm [1]: vgic interrupt IRQ1
> [ 0.498978] kvm [1]: virtual timer IRQ4
> [ 0.501267] futex hash table entries: 2048 (order: 6, 262144 bytes)
> [ 0.501394] audit: initializing netlink subsys (disabled)
> [ 0.501462] audit: type=2000 audit(0.495:1): initialized
> [ 0.501845] workingset: timestamp_bits=46 max_order=18 bucket_order=0
> [ 0.508960] squashfs: version 4.0 (2009/01/31) Phillip Lougher
> [ 0.509596] NFS: Registering the id_resolver key type
> [ 0.509632] Key type id_resolver registered
> [ 0.509645] Key type id_legacy registered
> [ 0.509665] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
> [ 0.509833] 9p: Installing v9fs 9p2000 file system support
> [ 0.512208] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 247)
> [ 0.512235] io scheduler noop registered
> [ 0.512349] io scheduler cfq registered (default)
> [ 0.513271] libphy: mdio_driver_register: phy-bcm-ns2-pci
> [ 0.514198] pinctrl-single f7010000.pinmux: 159 pins at pa ffff000008e81000 size 636
> [ 0.514612] pinctrl-single f7010800.pinmux: 163 pins at pa ffff000008e83800 size 652
> [ 0.514770] pinctrl-single f8001800.pinmux: 30 pins at pa ffff000008e85800 size 120
> [ 0.515809] pl061_gpio f8011000.gpio: PL061 GPIO chip @0x00000000f8011000 registered
> [ 0.516214] pl061_gpio f8012000.gpio: PL061 GPIO chip @0x00000000f8012000 registered
> [ 0.516610] pl061_gpio f8013000.gpio: PL061 GPIO chip @0x00000000f8013000 registered
> [ 0.516687] gpio gpiochip3: gpio-line-names specifies 9 line names but there are 8 lines on the chip
> [ 0.517038] pl061_gpio f8014000.gpio: PL061 GPIO chip @0x00000000f8014000 registered
> [ 0.517416] pl061_gpio f7020000.gpio: PL061 GPIO chip @0x00000000f7020000 registered
> [ 0.517796] pl061_gpio f7021000.gpio: PL061 GPIO chip @0x00000000f7021000 registered
> [ 0.518172] pl061_gpio f7022000.gpio: PL061 GPIO chip @0x00000000f7022000 registered
> [ 0.518577] pl061_gpio f7023000.gpio: PL061 GPIO chip @0x00000000f7023000 registered
> [ 0.518658] gpio gpiochip8: gpio-line-names specifies 9 line names but there are 8 lines on the chip
> [ 0.518999] pl061_gpio f7024000.gpio: PL061 GPIO chip @0x00000000f7024000 registered
> [ 0.519385] pl061_gpio f7025000.gpio: PL061 GPIO chip @0x00000000f7025000 registered
> [ 0.519774] pl061_gpio f7026000.gpio: PL061 GPIO chip @0x00000000f7026000 registered
> [ 0.520162] pl061_gpio f7027000.gpio: PL061 GPIO chip @0x00000000f7027000 registered
> [ 0.520550] pl061_gpio f7028000.gpio: PL061 GPIO chip @0x00000000f7028000 registered
> [ 0.520939] pl061_gpio f7029000.gpio: PL061 GPIO chip @0x00000000f7029000 registered
> [ 0.521324] pl061_gpio f702a000.gpio: PL061 GPIO chip @0x00000000f702a000 registered
> [ 0.521719] pl061_gpio f702b000.gpio: PL061 GPIO chip @0x00000000f702b000 registered
> [ 0.522107] pl061_gpio f702c000.gpio: PL061 GPIO chip @0x00000000f702c000 registered
> [ 0.522505] pl061_gpio f702d000.gpio: PL061 GPIO chip @0x00000000f702d000 registered
> [ 0.522884] pl061_gpio f702e000.gpio: PL061 GPIO chip @0x00000000f702e000 registered
> [ 0.523275] pl061_gpio f702f000.gpio: PL061 GPIO chip @0x00000000f702f000 registered
> [ 0.526086] xenfs: not registering filesystem on non-xen platform
> [ 0.528934] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
> [ 0.530124] SuperH (H)SCI(F) driver initialized
> [ 0.530364] msm_serial: driver initialized
> [ 0.536344] loop: module loaded
> [ 0.539526] hisi_sas: driver version v1.6
> [ 0.541976] libphy: Fixed MDIO Bus: probed
> [ 0.542702] tun: Universal TUN/TAP device driver, 1.6
> [ 0.542719] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
> [ 0.543688] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
> [ 0.543707] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
> [ 0.543804] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k
> [ 0.543821] igb: Copyright (c) 2007-2014 Intel Corporation.
> [ 0.543906] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.4.0-k
> [ 0.543930] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
> [ 0.544018] sky2: driver version 1.30
> [ 0.544551] VFIO - User Level meta-driver version: 0.3
> [ 0.546560] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
> [ 0.546590] ehci-pci: EHCI PCI platform driver
> [ 0.546638] ehci-platform: EHCI generic platform driver
> [ 0.546730] ehci-exynos: EHCI EXYNOS driver
> [ 0.546802] ehci-msm: Qualcomm On-Chip EHCI Host Controller
> [ 0.546866] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
> [ 0.546900] ohci-pci: OHCI PCI platform driver
> [ 0.546952] ohci-platform: OHCI generic platform driver
> [ 0.547024] ohci-exynos: OHCI EXYNOS driver
> [ 0.547324] usbcore: registered new interface driver usb-storage
> [ 0.547863] file system registered
> [ 0.548183] mousedev: PS/2 mouse device common for all mice
> [ 0.548621] input: HISI 65xx PowerOn Key as /devices/platform/f8000000.pmic/hi65xx-powerkey.0.auto/input/input0
> [ 0.549253] rtc-pl031 f8003000.rtc: rtc core: registered pl031 as rtc0
> [ 0.549459] rtc-pl031 f8004000.rtc: rtc core: registered pl031 as rtc1
> [ 0.549796] i2c /dev entries driver
> [ 0.552183] sdhci: Secure Digital Host Controller Interface driver
> [ 0.552207] sdhci: Copyright(c) Pierre Ossman
> [ 0.552403] Synopsys Designware Multimedia Card Interface Driver
> [ 0.553405] sdhci-pltfm: SDHCI platform and OF driver helper
> [ 0.554851] ledtrig-cpu: registered to indicate activity on CPUs
> [ 0.555695] usbcore: registered new interface driver usbhid
> [ 0.555717] usbhid: USB HID core driver
> [ 0.557233] NET: Registered protocol family 17
> [ 0.557320] 9pnet: Installing 9P2000 support
> [ 0.557383] Key type dns_resolver registered
> [ 0.557996] registered taskstats version 1
> [ 0.561690] f7111000.uart: ttyAMA1 at MMIO 0xf7111000 (irq = 8, base_baud = 0) is a PL011 rev2
> [ 0.562226] f7112000.uart: ttyAMA2 at MMIO 0xf7112000 (irq = 9, base_baud = 0) is a PL011 rev2
> [ 0.562553] f7113000.uart: ttyAMA3 at MMIO 0xf7113000 (irq = 10, base_baud = 0) is a PL011 rev2
> [ 1.916968] console [ttyAMA3] enabled
> [ 1.922080] ssp-pl022 f7106000.spi: ARM PL022 driver, device ID: 0x00041022
> [ 1.929144] ssp-pl022 f7106000.spi: mapped registers from 0x00000000f7106000 to ffff000008f03000
> [ 1.938007] ssp-pl022 f7106000.spi: Failed to work in dma mode, work without dma!
> [ 1.949535] f72c0000.usb supply vusb_d not found, using dummy regulator
> [ 1.956256] f72c0000.usb supply vusb_a not found, using dummy regulator
> [ 2.344873] dwc2 f72c0000.usb: EPs: 16, dedicated fifos, 1920 entries in SPRAM
> [ 2.353154] dwc2 f72c0000.usb: DWC OTG Controller
> [ 2.357891] dwc2 f72c0000.usb: new USB bus registered, assigned bus number 1
> [ 2.364979] dwc2 f72c0000.usb: irq 38, io mem 0x00000000
> [ 2.371082] hub 1-0:1.0: USB hub found
> [ 2.374866] hub 1-0:1.0: 1 port detected
> [ 2.382071] rtc-pl031 f8003000.rtc: setting system clock to 1970-01-01 00:00:19 UTC (19)
> [ 2.390486] LDO2_2V8: disabling
> [ 2.393639] LDO7_SDIO: disabling
> [ 2.396900] LDO10_2V85: disabling
> [ 2.400234] LDO13_1V8: disabling
> [ 2.403476] LDO14_2V8: disabling
> [ 2.406721] LDO17_2V5: disabling
> [ 2.409956] LDO19_3V0: disabling
> [ 2.413199] wlan-en-regulator: disabling
> [ 2.417135] ALSA device list:
> [ 2.420109] No soundcards found.
> [ 2.423712] uart-pl011 f7113000.uart: no DMA platform data
> [ 2.429585] Freeing unused kernel memory: 1024K (ffff800000c40000 - ffff800000d40000)
> Loading, please wait...
> starting version 228
> [ 2.479981] random: systemd-udevd: uninitialized urandom read (16 bytes read)
> [ 2.483570] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.483680] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.485404] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.485631] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.485859] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.486098] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.486305] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.486729] random: udevadm: uninitialized urandom read (16 bytes read)
> [ 2.486951] random: udevadm: uninitialized urandom read (16 bytes read)
> Begin: Loading essential drivers ... done.
> Begin: Running /scripts/init-premount ... done.
> Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
> Begin: Running /scripts/local-premount ... modprobe: can't change directory to '4.9.0-rc1-00251-g323792f': No such file or directory
> done.
> Begin: Waiting for root file system ... Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
> Begin: Running /scripts/local-block ... done.
>
> Thanks,
> Leo Yan
>
>
>
^ permalink raw reply
* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Cyrille Pitchen @ 2016-10-28 9:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027160406.25738-1-richard.genoud@gmail.com>
Le 27/10/2016 ? 18:04, Richard Genoud a ?crit :
> After commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
> when hardware handshake is enabled"), the hardware handshake wasn't
> functional anymore on Atmel platforms (beside SAMA5D2).
>
> To understand why, one has to understand the flag ATMEL_US_USMODE_HWHS
> first:
> Before commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
> when hardware handshake is enabled"), this flag was never set.
> Thus, the CTS/RTS where only handled by serial_core (and everything
> worked just fine).
>
> This commit introduced the use of the ATMEL_US_USMODE_HWHS flag,
> enabling it for all boards when the user space enables flow control.
>
> When the ATMEL_US_USMODE_HWHS is set, the Atmel USART controller
> handles a part of the flow control job:
> - disable the transmitter when the CTS pin gets high.
> - drive the RTS pin high when the DMA buffer transfer is completed or
> PDC RX buffer full or RX FIFO is beyond threshold. (depending on the
> controller version).
>
> NB: This feature is *not* mandatory for the flow control to work.
> (Nevertheless, it's very useful if low latencies are needed.)
>
> Now, the specifics of the ATMEL_US_USMODE_HWHS flag:
>
> - For platforms with DMAC and no FIFOs (sam9x25, sam9x35, sama5D3,
> sama5D4, sam9g15, sam9g25, sam9g35)* this feature simply doesn't work.
> ( source: https://lkml.org/lkml/2016/9/7/598 )
> Tested it on sam9g35, the RTS pins always stays up, even when RXEN=1
> or a new DMA transfer descriptor is set.
> => ATMEL_US_USMODE_HWHS must not be used for those platforms
>
> - For platforms with a PDC (sam926{0,1,3}, sam9g10, sam9g20, sam9g45,
> sam9g46)*, there's another kind of problem. Once the flag
> ATMEL_US_USMODE_HWHS is set, the RTS pin can't be driven anymore via
> RTSEN/RTSDIS in USART Control Register. The RTS pin can only be driven
> by enabling/disabling the receiver or setting RCR=RNCR=0 in the PDC
> (Receive (Next) Counter Register).
> => Doing this is beyond the scope of this patch and could add other
> bugs, so the original (and working) behaviour should be set for those
> platforms (meaning ATMEL_US_USMODE_HWHS flag should be unset).
>
> - For platforms with a FIFO (sama5d2)*, the RTS pin is driven according
> to the RX FIFO thresholds, and can be also driven by RTSEN/RTSDIS in
> USART Control Register. No problem here.
> (This was the use case of commit 1cf6e8fc8341 ("tty/serial: at91: fix
> RTS line management when hardware handshake is enabled"))
> NB: If the CTS pin declared as a GPIO in the DTS, (for instance
> cts-gpios = <&pioA PIN_PB31 GPIO_ACTIVE_LOW>), the transmitter will be
> disabled.
> => ATMEL_US_USMODE_HWHS flag can be set for this platform ONLY IF the
> CTS pin is not a GPIO.
>
> So, the only case when ATMEL_US_USMODE_HWHS can be enabled is when
> (atmel_use_fifo(port) &&
> !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
>
> Tested on all Atmel USART controller flavours:
> AT91SAM9G35-CM (DMAC flavour), AT91SAM9G20-EK (PDC flavour),
> SAMA5D2xplained (FIFO flavour).
>
> * the list may not be exhaustive
>
> Cc: <stable@vger.kernel.org> #4.4+ (beware, missing atmel_port variable)
> Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled")
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
thanks :)
> ---
> drivers/tty/serial/atmel_serial.c | 26 ++++++++++++++++++++++----
> 1 file changed, 22 insertions(+), 4 deletions(-)
>
> Note for -stable:
> This patch will apply on 4.4.x/4.8.x but compilation will fail due to
> a missing variable atmel_port (introduced in 4.9-rc1):
>
> static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> struct ktermios *old)
> {
> + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> unsigned long flags;
> unsigned int old_mode, mode, imr, quot, baud;
>
> Changes since v5:
> - fix typos
> - increase commentary
>
> Changes since v4:
> - the mctrl_gpio_use_rtscts() is gone since it was atmel_serial
> specific. (so patch 1 is gone)
> - patches 2 and 3 have been merged together since it didn't make
> a lot of sense to correct the GPIO case in one separate patch.
> - ATMEL_US_USMODE_HWHS is now unset for platform with PDC
>
> Changes since v3:
> - remove superfluous #include <linux/err.h> (thanks to Uwe)
> - rebase on next-20160930
>
> Changes since v2:
> - remove IS_ERR_OR_NULL() test in patch 1/3 as Uwe suggested.
> - fix typos in patch 2/3
> - rebase on next-20160927
> - simplify the logic in patch 3/3.
>
> Changes since v1:
> - Correct patch 1 with the error found by kbuild.
> - Add Alexandre's Acked-by on patch 2
> - Rewrite patch 3 logic in the light of the on-going discussion
> with Cyrille and Alexandre.
>
>
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index fd8aa1f4ba78..168b10cad47b 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> mode |= ATMEL_US_USMODE_RS485;
> } else if (termios->c_cflag & CRTSCTS) {
> /* RS232 with hardware handshake (RTS/CTS) */
> - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
> - dev_info(port->dev, "not enabling hardware flow control because DMA is used");
> - termios->c_cflag &= ~CRTSCTS;
> - } else {
> + if (atmel_use_fifo(port) &&
> + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
> + /*
> + * with ATMEL_US_USMODE_HWHS set, the controller will
> + * be able to drive the RTS pin high/low when the RX
> + * FIFO is above RXFTHRES/below RXFTHRES2.
> + * It will also disable the transmitter when the CTS
> + * pin is high.
> + * This mode is not activated if CTS pin is a GPIO
> + * because in this case, the transmitter is always
> + * disabled (there must be an internal pull-up
> + * responsible for this behaviour).
> + * If the RTS pin is a GPIO, the controller won't be
> + * able to drive it according to the FIFO thresholds,
> + * but it will be handled by the driver.
> + */
> mode |= ATMEL_US_USMODE_HWHS;
> + } else {
> + /*
> + * For platforms without FIFO, the flow control is
> + * handled by the driver.
> + */
> + mode |= ATMEL_US_USMODE_NORMAL;
> }
> } else {
> /* RS232 without hadware handshake */
>
^ permalink raw reply
* [PATCH v9 1/4] soc: mediatek: Refine scpsys to support multiple platform
From: James Liao @ 2016-10-28 9:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1d5cda95-467a-4f95-1cc9-b8f156271a54@gmail.com>
Hi Matthias,
Sorry for late reply due to our email service.
On Tue, 2016-10-25 at 16:04 +0200, Matthias Brugger wrote:
> Hi James,
>
> On 10/20/2016 10:56 AM, James Liao wrote:
> > -static int scpsys_probe(struct platform_device *pdev)
> > +static void init_clks(struct platform_device *pdev, struct clk *clk[CLK_MAX])
>
> I prefer struct clk **clk.
Okay.
> > +{
> > + int i;
> > +
> > + for (i = CLK_NONE + 1; i < CLK_MAX; i++)
> > + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
> > +}
> > +
> > +static struct scp *init_scp(struct platform_device *pdev,
> > + const struct scp_domain_data *scp_domain_data, int num)
> > {
> > struct genpd_onecell_data *pd_data;
> > struct resource *res;
> > - int i, j, ret;
> > + int i, j;
> > struct scp *scp;
> > - struct clk *clk[MT8173_CLK_MAX];
> > + struct clk *clk[CLK_MAX];
>
> should be *[CLK_MAX - 1] but I would prefer to define in the enum:
> CLK_MAX = CLK_VENC_LT,
After init_clks() the clk[] will have valid contents between
clk[1]..clk[CLK_MAX-1], so it's necessary to declare clk[] with CLK_MAX
elements.
> If you are ok with it, I can fix both of my comments when applying.
Yes. struct clk **clk can be applied directly. But I think clk[CLK_MAX]
should be kept in current implementation.
Best regards,
James
^ permalink raw reply
* [PATCH v2 3/3] reset: Add the TI SCI reset driver
From: Philipp Zabel @ 2016-10-28 9:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027214941.24641-4-afd@ti.com>
Hi Andrew,
is there (going to be) as stable branch I can base these on, or should I
just wait until the prerequisite patches appear in arm-soc/for-next?
Am Donnerstag, den 27.10.2016, 16:49 -0500 schrieb Andrew F. Davis:
> Some TI Keystone family of SoCs contain a system controller (like the
> Power Management Micro Controller (PMMC) on K2G SoCs) that manage the
> low-level device control (like clocks, resets etc) for the various
> hardware modules present on the SoC. These device control operations
> are provided to the host processor OS through a communication protocol
> called the TI System Control Interface (TI SCI) protocol.
>
> This patch adds a reset driver that communicates to the system
> controller over the TI SCI protocol for performing reset management
> of various devices present on the SoC. Various reset functionalities
> are achieved by the means of different TI SCI device operations
> provided by the TI SCI framework.
>
> Signed-off-by: Andrew F. Davis <afd@ti.com>
> [s-anna at ti.com: documentation changes, revised commit message]
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
> MAINTAINERS | 1 +
> drivers/reset/Kconfig | 9 ++
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-ti-sci.c | 262 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 273 insertions(+)
> create mode 100644 drivers/reset/reset-ti-sci.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index accf991..b93d91a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11901,6 +11901,7 @@ F: include/dt-bindings/clock/k2g.h
> F: drivers/clk/keystone/sci-clk.c
> F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt
> F: include/dt-bindings/reset/k2g.h
> +F: drivers/reset/reset-ti-sci.c
>
> THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
> M: Hans Verkuil <hverkuil@xs4all.nl>
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 06d9fa2..4c21c9d 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -66,6 +66,15 @@ config RESET_SUNXI
> help
> This enables the reset driver for Allwinner SoCs.
>
> +config RESET_TI_SCI
> + tristate "TI System Control Interface (TI-SCI) reset driver"
> + depends on RESET_CONTROLLER
> + depends on TI_SCI_PROTOCOL
> + help
> + This enables the reset driver support over TI System Control Interface
> + available on some new TI SoCs. If you wish to use reset resources
> + managed by the TI System Controller, say Y here. Otherwise, say N.
> +
> config TI_SYSCON_RESET
> tristate "TI SYSCON Reset Driver"
> depends on HAS_IOMEM
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index bbe7026..36321f2 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
> obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
> obj-$(CONFIG_RESET_STM32) += reset-stm32.o
> obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
> +obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
> obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
> obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
> diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c
> new file mode 100644
> index 0000000..42ccf12
> --- /dev/null
> +++ b/drivers/reset/reset-ti-sci.c
> @@ -0,0 +1,262 @@
> +/*
> + * Texas Instrument's System Control Interface (TI-SCI) reset driver
> + *
> + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
> + * Andrew F. Davis <afd@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/soc/ti/ti_sci_protocol.h>
> +
> +/**
> + * struct ti_sci_reset_control - reset control structure
> + * @dev_id: SoC-specific device identifier
> + * @reset_mask: reset mask to use for toggling reset
> + */
> +struct ti_sci_reset_control {
> + u32 dev_id;
> + u32 reset_mask;
> +};
> +
> +/**
> + * struct ti_sci_reset_data - reset controller information structure
> + * @rcdev: reset controller entity
> + * @dev: reset controller device pointer
> + * @sci: TI SCI handle used for communication with system controller
> + * @idr: idr structure for mapping ids to reset control structures
> + */
> +struct ti_sci_reset_data {
> + struct reset_controller_dev rcdev;
> + struct device *dev;
> + const struct ti_sci_handle *sci;
> + struct idr idr;
> +};
> +
> +#define to_ti_sci_reset_data(p) \
> + container_of((p), struct ti_sci_reset_data, rcdev)
> +
> +/**
> + * ti_sci_reset_set() - program a device's reset
> + * @rcdev: reset controller entity
> + * @id: ID of the reset to toggle
> + * @assert: boolean flag to indicate assert or deassert
> + *
> + * This is a common internal function used to assert or deassert a device's
> + * reset using the TI SCI protocol. The device's reset is asserted if the
> + * @assert argument is true, or deasserted if @assert argument is false.
> + * The mechanism itself is a read-modify-write procedure, the current device
> + * reset register is read using a TI SCI device operation, the new value is
> + * set or un-set using the reset's mask, and the new reset value written by
> + * using another TI SCI device operation.
> + *
> + * Return: 0 for successful request, else a corresponding error value
> + */
> +static int ti_sci_reset_set(struct reset_controller_dev *rcdev,
> + unsigned long id, bool assert)
> +{
> + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
> + const struct ti_sci_handle *sci = data->sci;
> + const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
> + struct ti_sci_reset_control *control;
> + u32 reset_state;
> + int ret;
> +
> + control = idr_find(&data->idr, id);
> + if (!control)
> + return -EINVAL;
> +
> + ret = dev_ops->get_device_resets(sci, control->dev_id,
> + &reset_state);
> + if (ret)
> + return ret;
> +
> + if (assert)
> + reset_state |= control->reset_mask;
> + else
> + reset_state &= ~control->reset_mask;
> +
> + return dev_ops->set_device_resets(sci, control->dev_id,
> + reset_state);
Without any locking? Maybe the read-modify-write could just be moved one
level down with an update_bits type of callback in the ti_sci_dev_ops.
> +}
> +
> +/**
> + * ti_sci_reset_assert() - assert device reset
> + * @rcdev: reset controller entity
> + * @id: ID of the reset to be asserted
> + *
> + * This function implements the reset driver op to assert a device's reset
> + * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
> + * with the corresponding parameters as passed in, but with the @assert
> + * argument set to true for asserting the reset.
> + *
> + * Return: 0 for successful request, else a corresponding error value
> + */
> +static int ti_sci_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + return ti_sci_reset_set(rcdev, id, true);
> +}
> +
> +/**
> + * ti_sci_reset_deassert() - deassert device reset
> + * @rcdev: reset controller entity
> + * @id: ID of the reset to be deasserted
> + *
> + * This function implements the reset driver op to deassert a device's reset
> + * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
> + * with the corresponding parameters as passed in, but with the @assert
> + * argument set to false for deasserting the reset.
> + *
> + * Return: 0 for successful request, else a corresponding error value
> + */
> +static int ti_sci_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + return ti_sci_reset_set(rcdev, id, false);
> +}
> +
> +/**
> + * ti_sci_reset_status() - check device reset status
> + * @rcdev: reset controller entity
> + * @id: ID of reset to be checked
> + *
> + * This function implements the reset driver op to return the status of a
> + * device's reset using the TI SCI protocol. The reset register value is read
> + * by invoking the TI SCI device opertation .get_device_resets(), and the
> + * status of the specific reset is extracted and returned using this reset's
> + * reset mask.
> + *
> + * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
> + */
> +static int ti_sci_reset_status(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
> + const struct ti_sci_handle *sci = data->sci;
> + const struct ti_sci_dev_ops *dev_ops = &sci->ops.dev_ops;
> + struct ti_sci_reset_control *control;
> + u32 reset_state;
> + int ret;
> +
> + control = idr_find(&data->idr, id);
> + if (!control)
> + return -EINVAL;
> +
> + ret = dev_ops->get_device_resets(sci, control->dev_id,
> + &reset_state);
> + if (ret)
> + return ret;
> +
> + return reset_state & control->reset_mask;
> +}
> +
> +static struct reset_control_ops ti_sci_reset_ops = {
> + .assert = ti_sci_reset_assert,
> + .deassert = ti_sci_reset_deassert,
> + .status = ti_sci_reset_status,
> +};
> +
> +/**
> + * ti_sci_reset_of_xlate() - translate a set of OF arguments to a reset ID
> + * @rcdev: reset controller entity
> + * @reset_spec: OF reset argument specifier
> + *
> + * This function performs the translation of the reset argument specifier
> + * values defined in a reset consumer device node. The function allocates a
> + * reset control structure for that device reset, and will be used by the
> + * driver for performing any reset functions on that reset. An idr structure
> + * is allocated and used to map to the reset control structure. This idr
> + * is used by the driver to do reset lookups.
> + *
> + * Return: 0 for successful request, else a corresponding error value
> + */
> +static int ti_sci_reset_of_xlate(struct reset_controller_dev *rcdev,
> + const struct of_phandle_args *reset_spec)
> +{
> + struct ti_sci_reset_data *data = to_ti_sci_reset_data(rcdev);
> + struct ti_sci_reset_control *control;
> +
> + if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
> + return -EINVAL;
> +
> + control = devm_kzalloc(data->dev, sizeof(*control), GFP_KERNEL);
> + if (!control)
> + return -ENOMEM;
> +
> + control->dev_id = reset_spec->args[0];
> + control->reset_mask = reset_spec->args[1];
> +
> + return idr_alloc(&data->idr, control, 0, 0, GFP_KERNEL);
> +}
> +
> +static const struct of_device_id ti_sci_reset_of_match[] = {
> + { .compatible = "ti,sci-reset", },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, ti_sci_reset_of_match);
> +
> +static int ti_sci_reset_probe(struct platform_device *pdev)
> +{
> + struct ti_sci_reset_data *data;
> +
> + if (!pdev->dev.of_node)
> + return -ENODEV;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->sci = devm_ti_sci_get_handle(&pdev->dev);
> + if (IS_ERR(data->sci))
> + return PTR_ERR(data->sci);
> +
> + data->rcdev.ops = &ti_sci_reset_ops;
> + data->rcdev.owner = THIS_MODULE;
> + data->rcdev.of_node = pdev->dev.of_node;
> + data->rcdev.of_reset_n_cells = 2;
> + data->rcdev.of_xlate = ti_sci_reset_of_xlate;
> + data->dev = &pdev->dev;
> + idr_init(&data->idr);
> +
> + platform_set_drvdata(pdev, data);
> +
> + return reset_controller_register(&data->rcdev);
> +}
> +
> +static int ti_sci_reset_remove(struct platform_device *pdev)
> +{
> + struct ti_sci_reset_data *data = platform_get_drvdata(pdev);
> +
> + reset_controller_unregister(&data->rcdev);
> +
> + idr_destroy(&data->idr);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ti_sci_reset_driver = {
> + .probe = ti_sci_reset_probe,
> + .remove = ti_sci_reset_remove,
> + .driver = {
> + .name = "ti-sci-reset",
> + .of_match_table = ti_sci_reset_of_match,
> + },
> +};
> +module_platform_driver(ti_sci_reset_driver);
> +
> +MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
> +MODULE_DESCRIPTION("TI System Control Interface (TI SCI) Reset driver");
> +MODULE_LICENSE("GPL v2");
regards
Philipp
^ permalink raw reply
* [PATCH] drm/rockchip: analogix_dp: add supports for regulators in edp IP
From: Randy Li @ 2016-10-28 9:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6d050f06-996f-5ecc-20f9-587299ee34c7@rock-chips.com>
On 10/28/2016 05:11 PM, Shawn Lin wrote:
> On 2016/10/23 3:18, Randy Li wrote:
>> I found if eDP_AVDD_1V0 and eDP_AVDD_1V8 are not been power at
>> RK3288, once trying to enable the pclk clock, the kernel would dead.
>> This patch would try to enable them first. The eDP_AVDD_1V8 more
>> likely to be applied to eDP phy, but I have no time to confirmed
>> it yet.
>
> Comfirm it or at least someone should be able to answer your
> question, Mark?
I just forget to ask the IC department, the TRM didn't cover that.
>
> Have you considered to add some details about vcc-supply and vccio-
> supply for your analogix_dp-rockchip.txt ?
>
> From your commit msg, these two properties are more likely to be
> required but the code itself tell me them should be optional(from the
> point of backward compatibility, it should also be optinoal).
Yes, I keep it optional for the same reason. Most of boards won't turn
off those power supply and may use some fixed regulators.
>
>>
>> Signed-off-by: Randy Li <ayaka@soulik.info>
>> ---
>> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 25
>> +++++++++++++++++++++++++
>> 1 file changed, 25 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> index 8548e82..6bf0441 100644
>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> @@ -17,6 +17,7 @@
>> #include <linux/of_device.h>
>> #include <linux/of_graph.h>
>> #include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> #include <linux/reset.h>
>> #include <linux/clk.h>
>>
>> @@ -70,6 +71,7 @@ struct rockchip_dp_device {
>> struct clk *grfclk;
>> struct regmap *grf;
>> struct reset_control *rst;
>> + struct regulator_bulk_data supplies[2];
>>
>> struct work_struct psr_work;
>> spinlock_t psr_lock;
>> @@ -146,6 +148,13 @@ static int rockchip_dp_poweron(struct
>> analogix_dp_plat_data *plat_data)
>>
>> cancel_work_sync(&dp->psr_work);
>>
>> + ret = regulator_bulk_enable(ARRAY_SIZE(dp->supplies),
>> + dp->supplies);
>> + if (ret) {
>> + dev_err(dp->dev, "failed to enable vdd supply %d\n", ret);
>> + return ret;
>> + }
>> +
>> ret = clk_prepare_enable(dp->pclk);
>> if (ret < 0) {
>> dev_err(dp->dev, "failed to enable pclk %d\n", ret);
>> @@ -168,6 +177,9 @@ static int rockchip_dp_powerdown(struct
>> analogix_dp_plat_data *plat_data)
>>
>> clk_disable_unprepare(dp->pclk);
>>
>> + regulator_bulk_disable(ARRAY_SIZE(dp->supplies),
>> + dp->supplies);
>> +
>> return 0;
>> }
>>
>> @@ -323,6 +335,19 @@ static int rockchip_dp_init(struct
>> rockchip_dp_device *dp)
>> return PTR_ERR(dp->rst);
>> }
>>
>> + dp->supplies[0].supply = "vcc";
>> + dp->supplies[1].supply = "vccio";
>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dp->supplies),
>> + dp->supplies);
>> + if (ret < 0) {
>> + dev_err(dev, "failed to get regulators: %d\n", ret);
>> + }
>> + ret = regulator_bulk_enable(ARRAY_SIZE(dp->supplies),
>> + dp->supplies);
>> + if (ret < 0) {
>> + dev_err(dev, "failed to enable regulators: %d\n", ret);
>> + }
>> +
>> ret = clk_prepare_enable(dp->pclk);
>> if (ret < 0) {
>> dev_err(dp->dev, "failed to enable pclk %d\n", ret);
>>
>
>
--
Randy Li
The third produce department
===========================================================================
This email message, including any attachments, is for the sole
use of the intended recipient(s) and may contain confidential and
privileged information. Any unauthorized review, use, disclosure or
distribution is prohibited. If you are not the intended recipient, please
contact the sender by reply e-mail and destroy all copies of the original
message. [Fuzhou Rockchip Electronics, INC. China mainland]
===========================================================================
^ permalink raw reply
* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Richard Genoud @ 2016-10-28 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027180229.5faqrvxa2a4pos7i@pengutronix.de>
2016-10-27 20:02 GMT+02:00 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
> Hello Richard,
>
> On Thu, Oct 27, 2016 at 06:04:06PM +0200, Richard Genoud wrote:
>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>> index fd8aa1f4ba78..168b10cad47b 100644
>> --- a/drivers/tty/serial/atmel_serial.c
>> +++ b/drivers/tty/serial/atmel_serial.c
>> @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
>> mode |= ATMEL_US_USMODE_RS485;
>> } else if (termios->c_cflag & CRTSCTS) {
>> /* RS232 with hardware handshake (RTS/CTS) */
>> - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
>> - dev_info(port->dev, "not enabling hardware flow control because DMA is used");
>> - termios->c_cflag &= ~CRTSCTS;
>> - } else {
>> + if (atmel_use_fifo(port) &&
>> + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
>> + /*
>> + * with ATMEL_US_USMODE_HWHS set, the controller will
>> + * be able to drive the RTS pin high/low when the RX
>> + * FIFO is above RXFTHRES/below RXFTHRES2.
>> + * It will also disable the transmitter when the CTS
>> + * pin is high.
>> + * This mode is not activated if CTS pin is a GPIO
>> + * because in this case, the transmitter is always
>> + * disabled (there must be an internal pull-up
>> + * responsible for this behaviour).
>> + * If the RTS pin is a GPIO, the controller won't be
>> + * able to drive it according to the FIFO thresholds,
>> + * but it will be handled by the driver.
>> + */
>> mode |= ATMEL_US_USMODE_HWHS;
>
> You use
>
> !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)
>
> as indicator that the cts mode of the respective pin is used. Is this
> reliable? (It's not if there are machines that don't use CTS, neither as
> gpio nor using the hardware function.) Maybe this needs a dt property to
> indicate that there is no (hw)handshaking available?
I used that to filter-out the case where CTS is a GPIO.
Now, for the machines that don't use CTS neither as GPIO nor using the
hardware function, it's a whole different story, beyond the scope of this patch.
And like you said, a DT property could be useful to handle this case.
( It's a little bit like if there was an RS232 cable with just TX/RX/GND, but
this will be way harder to detect :) )
Anyway, patches are welcome to handle that, but I don't think it belongs
in this one.
>> + } else {
>> + ...
>> }
>
> Best regards
> Uwe
>
regards,
Richard
^ permalink raw reply
* [GIT PULL] Rockchip dts64 fixes for 4.9-rc
From: Heiko Stuebner @ 2016-10-28 9:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd, Kevin, Olof,
please find below two fixes for 64bit Rockchip boards. One makes
binds/unbinds fail and the other drops one unnecessary property.
Please pull.
Thanks
Heiko
The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.9-rockchip-dts64-fixes1
for you to fetch changes up to 7c6273194445fe1316084d3096f9311c3dfa4da6:
arm64: dts: rockchip: remove the abuse of keep-power-in-suspend (2016-10-18 20:03:54 +0200)
----------------------------------------------------------------
Correct regulator handling on Rockchip arm64 boards to make
bind/unbind calls work correctly and remove a sdio-only
property from non-sdio mmc hosts, that accidentially was
added there.
----------------------------------------------------------------
Shawn Lin (2):
arm64: dts: rockchip: remove always-on and boot-on from vcc_sd
arm64: dts: rockchip: remove the abuse of keep-power-in-suspend
arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts | 3 ---
arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts | 4 ----
2 files changed, 7 deletions(-)
^ permalink raw reply
* [PATCH] arm64: mm: Fix memmap to be initialized for the entire section
From: Robert Richter @ 2016-10-28 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027160136.GD24290@arm.com>
On 27.10.16 17:01:36, Will Deacon wrote:
> Hi Robert,
>
> On Mon, Oct 17, 2016 at 08:58:01PM +0200, Robert Richter wrote:
> > Mark, Will, any opinion here?
>
> Having looking at this, I'm inclined to agree with you; pfn_valid() is
> all about whether the underlying mem_map (struct page *) entry exists,
> not about whether the page is mappable or not.
>
> That said, setting the zone for pages representing NOMAP memory feels
> like a slippery slope to losing information about them being NOMAP in
> the first place and the whole problem getting out-of-hand. Whilst I'm
> happy for pfn_valid() to return true (in the sense that we're within
> bounds of mem_map etc), I'm less happy that we're also saying that the
> struct page contains useful information, such as the zone and the node
> information, which is then subsequently used by the NUMA code.
Let's see it in a different way, pfns and the struct page assigned to
each of it is about *physical* memory. The system knows all the
memory, some is free, some reserved and some marked NOMAP. Regardless
of the mapping of the page the mm code maintains and uses that
information.
There are assumptions on validity and checks in the code that now
cause problems due to partly or non-existing data about nomap pages.
This inconsistency is dangerous since a problem may occur any time
then the page area is accessed first, thus a system may crash randomly
depending on the memory access. Luckily, in my case it triggered
reproducible while loading initrd during boot.
I also think that this is not only NUMA related. E.g. the following
bug report is probably also related:
https://bugzilla.redhat.com/show_bug.cgi?id=1387793
> On top of that, pfn_valid is used in other places as a coarse "is this
> memory?" check, and will cause things like ioremap to fail whereas it
> wouldn't at the moment.
IMO this is a misuse of pfn_valid() that needs to be fixed with
additional checks, e.g. traversing memblocks.
> It feels to me like NOMAP memory is a new type
> of memory where there *is* a struct page, but it shouldn't be used for
> anything.
IMO, a NOMAP page should just be handled like a reserved page except
that the page is marked reserved. See free_low_memory_core_early().
Thus, NOMAP pages are not in the free pages list or set to reserved.
It is simply not available for mapping at all. Isn't that exactly what
it should be?
I also did not yet understand the benefit of the differentiation
between NOMAP and reserved and the original motivation for its
implementation. I looked through the mail threads but could not find
any hint. The only difference I see now is that it is not listed as a
reserved page, but as long as it is not freed it should behave the
same. I remember the case to handle memory different (coherency,
etc.), but are not sure here. Ard, could you explain this?
> I don't think pfn_valid can describe that, given the way it's
> currently used, and flipping the logic is just likely to move the problem
> elsewhere.
>
> What options do we have for fixing this in the NUMA code?
Out of my mind:
1) Treat NOMAP pages same as reserved pages (my patch).
2) Change mm code to allow arch specific early_pfn_valid().
3) Fix mm code to only access stuct page (of a zone) if pfn_valid() is
true.
There can be more alternatives. IMO:
* We shouldn't touch generic mm code.
* We should maintain a valid struct page for all pages in a sections.
* We should only traverse memblock where really necessary (arm64
only).
* I don't think this problem is numa specific.
-Robert
^ permalink raw reply
* [PATCH 1/1] ARM: dts: imx6ul-14x14-evk: add USB dual-role support
From: Peter Chen @ 2016-10-28 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1470128903-942-1-git-send-email-peter.chen@nxp.com>
On Tue, Aug 2, 2016 at 5:08 PM, Peter Chen <peter.chen@nxp.com> wrote:
> With commit 851ce932242d ("usb: chipidea: otg: don't wait vbus
> drops below BSV when starts host"), the driver can support
> enabling vbus output without software control, so this board
> (control vbus output through ID pin) can support dual-role now.
>
> Signed-off-by: Peter Chen <peter.chen@nxp.com>
> ---
> arch/arm/boot/dts/imx6ul-14x14-evk.dts | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
> index e281d50..c5cf942 100644
> --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts
> +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
> @@ -225,7 +225,7 @@
> };
>
> &usbotg1 {
> - dr_mode = "peripheral";
> + dr_mode = "otg";
> status = "okay";
> };
>
Ping....
Peter
^ permalink raw reply
* [PATCH] drm/rockchip: analogix_dp: add supports for regulators in edp IP
From: Shawn Lin @ 2016-10-28 9:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477163933-13140-1-git-send-email-ayaka@soulik.info>
On 2016/10/23 3:18, Randy Li wrote:
> I found if eDP_AVDD_1V0 and eDP_AVDD_1V8 are not been power at
> RK3288, once trying to enable the pclk clock, the kernel would dead.
> This patch would try to enable them first. The eDP_AVDD_1V8 more
> likely to be applied to eDP phy, but I have no time to confirmed
> it yet.
Comfirm it or at least someone should be able to answer your
question, Mark?
Have you considered to add some details about vcc-supply and vccio-
supply for your analogix_dp-rockchip.txt ?
From your commit msg, these two properties are more likely to be
required but the code itself tell me them should be optional(from the
point of backward compatibility, it should also be optinoal).
>
> Signed-off-by: Randy Li <ayaka@soulik.info>
> ---
> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 8548e82..6bf0441 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -17,6 +17,7 @@
> #include <linux/of_device.h>
> #include <linux/of_graph.h>
> #include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> #include <linux/reset.h>
> #include <linux/clk.h>
>
> @@ -70,6 +71,7 @@ struct rockchip_dp_device {
> struct clk *grfclk;
> struct regmap *grf;
> struct reset_control *rst;
> + struct regulator_bulk_data supplies[2];
>
> struct work_struct psr_work;
> spinlock_t psr_lock;
> @@ -146,6 +148,13 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
>
> cancel_work_sync(&dp->psr_work);
>
> + ret = regulator_bulk_enable(ARRAY_SIZE(dp->supplies),
> + dp->supplies);
> + if (ret) {
> + dev_err(dp->dev, "failed to enable vdd supply %d\n", ret);
> + return ret;
> + }
> +
> ret = clk_prepare_enable(dp->pclk);
> if (ret < 0) {
> dev_err(dp->dev, "failed to enable pclk %d\n", ret);
> @@ -168,6 +177,9 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
>
> clk_disable_unprepare(dp->pclk);
>
> + regulator_bulk_disable(ARRAY_SIZE(dp->supplies),
> + dp->supplies);
> +
> return 0;
> }
>
> @@ -323,6 +335,19 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
> return PTR_ERR(dp->rst);
> }
>
> + dp->supplies[0].supply = "vcc";
> + dp->supplies[1].supply = "vccio";
> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dp->supplies),
> + dp->supplies);
> + if (ret < 0) {
> + dev_err(dev, "failed to get regulators: %d\n", ret);
> + }
> + ret = regulator_bulk_enable(ARRAY_SIZE(dp->supplies),
> + dp->supplies);
> + if (ret < 0) {
> + dev_err(dev, "failed to enable regulators: %d\n", ret);
> + }
> +
> ret = clk_prepare_enable(dp->pclk);
> if (ret < 0) {
> dev_err(dp->dev, "failed to enable pclk %d\n", ret);
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* [PATCH 4/5] ARM: davinci: enable LEDs default-on trigger in default config
From: Sekhar Nori @ 2016-10-28 9:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <be478f0a-bd10-7241-7e9d-20dfc1beaa30@lechnology.com>
On Thursday 27 October 2016 09:19 PM, David Lechner wrote:
> Yes, module is OK here.
Here is the patch I pushed to v4.10/defconfig.
Thanks,
Sekhar
---8<---
From: David Lechner <david@lechnology.com>
Date: Fri, 21 Oct 2016 13:36:56 -0500
Subject: [PATCH] ARM: davinci_all_defconfig: enable LED default-on trigger
The LEDs default-on trigger is nice to have. For example, it can be used
to configure a LED as a power indicator.
Signed-off-by: David Lechner <david@lechnology.com>
[nsekhar at ti.com: build as module, subject line fixes]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
arch/arm/configs/davinci_all_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index 513978eaf03d..b5e978ff177f 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -180,6 +180,7 @@ CONFIG_LEDS_GPIO=m
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_OMAP=m
CONFIG_DMADEVICES=y
--
2.9.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox