summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill McVicker <willmcvicker@google.com>2022-06-02 09:40:14 -0700
committerWill McVicker <willmcvicker@google.com>2022-06-02 09:43:50 -0700
commit7f6a736b208c7fb78f0902ca0b793b885115ac95 (patch)
tree8e8c22cd1b4430df6bc1267d8fae32eacce14207
parentbcfd429733db3c4e01a9ef07e7c4826c52b8049e (diff)
parent28826da1deae49f5a942bb7b4621944360933440 (diff)
downloadtrusty-7f6a736b208c7fb78f0902ca0b793b885115ac95.tar.gz
Merge 'android13-gs-pixel-5.15-gs101' into 'android13-gs-pixel-5.15'
* commit '5ff74e8ea23b6027946af60b485db4d45bf975b6': (494 commits) Slider: Add cfg80211 & mac80211 as vendor modules. soc: google: hardlockup-debug: Print Mem-Info when WDT kleaf: update dt-bindings to be generic kleaf: update the readme commands Revert "usb: typec: tcpci_max77759: stub for tcpm_is_debouncing()" Revert "slider_gki: enable CONFIG_VH_SCHED" Revert "Revert "scsi: ufs: ufs-exynos: update hba suspend vops"" Revert "drivers: thermal: update milliwatts references" Revert "scsi: ufs: ufs-exynos: update hba suspend vops" Revert "scsi: ufs: update to new wrapped key api" Revert "usb: dwc3: remove duplicated definitions" Revert "cpufreq: acme: flag updates to cpufreq_policy" Revert "iommu/samsung: drop IOVA cookie management" Revert "cpufreq: acme: fix thermal API for 5.17-rc2" Revert "Revert "tty: serial: exynos_tty: remove duplicated definitions"" Revert "soc/google/cpif: replace PDE_DATA as pde_data" Revert "ANDROID: Fixup spi_driver remove functions" Revert "media: mfc/smfc: Fix depends on VIDEO_V4L2" Revert "dma-buf-map: Rename to iosys-map" Revert "usb: dwc3: remove duplicate DWC3_GFLADJ_REFCLK_FLADJ_MASK" Revert "google/debug: update path to debug_kinfo.h" Revert "serial: exynos: update exynos_serial_console_putchar" Revert "iommu/samsung:remove aux-domain interfaces usage" Revert "dts/google: tpu: disable ssmt" Revert "Revert "dma-buf: Fix build for shrinker controlled page pool"" Revert "Revert "Revert "ANDROID: dma-buf: heaps: Add a shrinker controlled page pool""" Revert "Revert "dma-buf: Fix build for deferred-free-helper.h"" Revert "Revert "Revert "ANDROID: dma-buf: heaps: Add deferred-free-helper library code""" Revert "ANDROID: dma-buf: heaps: fix dma-buf heap pool pages stat" kleaf: Add kleaf tests for kernel_images kleaf: Move SLIDER_DTBOS to a global variable. kleaf: Move SLIDER_DTBOS to a global variable. kleaf: build abi for slider vendor_hook: sched: Add control for reduce_prefer_idle usb: dwc3: cancel gadget retry during device reboot arm64/dts: devfreq: add boot_info google/debug: ehld: handle hrtimers correctly in CPUHP and CPUPM Revert "google/debug: ehld: stop and restart hrtimer at CPU PM" google/debug: ehld: fix exynos_ehld_stop_cpu() devfreq: add sysfs node "cancel_boot_freq" aoc/alsa: dts: change the name for immersive playback aoc/alsa: dt-bindings: change the name for immersive playback arm64/dts: Add board_id and board_rev to aoc pcie: exynos: Skip PHY isloation on hot reset test Revert "vendor_hook: sched: Implement vendor group util" Revert "vendor_hook: sched: Check if cfs_rq->curr is a task" gvotable: export run_election API with force_callback parameter usb: have gvotable callback return an error code gvotable: have callback return an error code arm64/dts: enable battery pairing feature vendor_hook: sched: Add trace for compute_energy vh: sched: rt: prefer to overutilized CPU from unfit CPU soc/google/cpif: Keep DIT downstream netdev until removeDownstream vendor_hook: sched: revert back to use most_spare_cap_cpu media: mfc: move the mfc_alloc_codec_buffers() usb: dwc3: move the operation for burst mode setting arm64/dts: set bhi algo_ver and threshold vendor_hook: sched: Change the uclamp max of low prio tasks usb: phy: limit the string length in phy attribute google/debug: eat: use polling api for channel operations google/debug: eat: fix mbox ipc race condition media: mfc: fix KASAN use-after-free case misc: logbuffer: Fix a deadlock arm64/dts: gs101: Update default target_load for ALT DVFS ANDROID: trusty: add a toggle for running trusty work in higher priority Revert "trusty: add a toggle for using high prio WQ" pogo_transport: Configure USB_MUX_POGO_SEL Revert "vendor_hook: sched: Refine vendor group uclamp update" vendor_hook: sched: Refine RT util check usb: dwc3: disable INCR undefined length burst mode kleaf: build abi for slider tcpci_max77759: Reset the OVP if Vbus times out build.config.gs101: enable kunit kernel arg kleaf: Add log=info to slider. kleaf: Add log=info to slider. kleaf: Explicitly set build_initramfs. kleaf: Explicitly set build_initramfs. Add dw3000-core-tests.ko to the blocklist kleaf: re-enable the vendor_dlkm blocklist kleaf: add missing pixel_em.ko kleaf: Add slider_unstripped_modules_archive. kleaf: Move definitions to slider.bzl. kleaf: Add slider_unstripped_modules_archive. kleaf: Move definitions to slider.bzl. iommu/samsung: add missing unmap_pages op kleaf: update build command in README.md kleaf: Fix KCONFIG_EXT_MODULES_PREFIX for kleaf --config=local builds. Rename merge-from-mainline.sh build.config.gs101: drop the boot ramdisk PRE_DEFCONFIG_CMDS does not write to source tree. PRE_DEFCONFIG_CMDS does not write to source tree. merge-from-mainline: update the script to soc: google: bcm_dbg: check copy_to_user return value drivers: thermal: update milliwatts references google/debug: ehld: stop and restart hrtimer at CPU PM usb: dwc3: wait for pm suspend for USB host usb: dwc3: remove conditional operator usb: dwc3: release the lock if device is suspended usb: dwc3: wait for pm suspend when cable is plug-in vendor_hook: sched: Support RT task util ... Change-Id: I6f1ffd50ee4379247eef9319d1ff27dfe6599260 Signed-off-by: Will McVicker <willmcvicker@google.com>
-rw-r--r--drivers/trusty/Kconfig13
-rw-r--r--drivers/trusty/trusty-ipc.c137
-rw-r--r--drivers/trusty/trusty-log.c219
-rw-r--r--drivers/trusty/trusty-virtio.c19
-rw-r--r--drivers/trusty/trusty.c43
-rw-r--r--include/linux/trusty/trusty.h27
-rw-r--r--include/uapi/linux/trusty/ipc.h23
7 files changed, 386 insertions, 95 deletions
diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig
index 2f0e30c..fcde7f0 100644
--- a/drivers/trusty/Kconfig
+++ b/drivers/trusty/Kconfig
@@ -88,6 +88,19 @@ config TRUSTY_DMA_BUF_FFA_TAG
If set to N, a default implementation which returns 0 will be used.
+config TRUSTY_DMA_BUF_SHARED_MEM_ID
+ bool "Availability of trusty_dma_buf_get_shared_mem_id"
+ default n
+ help
+ Whether trusty_dma_buf_get_shared_mem_id is provided on this platform.
+ Providing this function allows the platform to manage memory
+ transaction life cycle of DMA bufs independently of Trusty IPC driver.
+ The latter can query trusty_shared_mem_id_t value allocated for a
+ given DMA buf using trusty_dma_buf_get_shared_mem_id interface.
+
+ If set to N, a default implementation which does not allocate any IDs
+ will be used.
+
config TRUSTY_CRASH_IS_PANIC
bool "When trusty panics, then panic the kernel"
help
diff --git a/drivers/trusty/trusty-ipc.c b/drivers/trusty/trusty-ipc.c
index 7ac586e..a30e02a 100644
--- a/drivers/trusty/trusty-ipc.c
+++ b/drivers/trusty/trusty-ipc.c
@@ -165,10 +165,14 @@ struct tipc_shared_handle {
struct rb_node node;
struct tipc_shm tipc;
struct tipc_virtio_dev *vds;
- struct sg_table *sgt;
- struct dma_buf_attachment *attach;
struct dma_buf *dma_buf;
bool shared;
+ /*
+ * Following fields are only used if dma_buf does not own a
+ * trusty_shared_mem_id_t.
+ */
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
};
static struct class *tipc_class;
@@ -288,7 +292,13 @@ static void _free_vds(struct kref *kref)
{
struct tipc_virtio_dev *vds =
container_of(kref, struct tipc_virtio_dev, refcount);
- /* If this WARN triggers, we're leaking remote memory references. */
+ /*
+ * If this WARN triggers, we're leaking remote memory references.
+ *
+ * No need to lock shared_handles_lock. All references to this lock
+ * should already be gone by this point, since we are freeing it in this
+ * function.
+ */
WARN_ON(!RB_EMPTY_ROOT(&vds->shared_handles));
kfree(vds);
}
@@ -550,22 +560,51 @@ static struct device *tipc_shared_handle_dev(struct tipc_shared_handle
return shared_handle->vds->vdev->dev.parent->parent;
}
+static bool is_same_memory_region(struct tipc_shared_handle *h1,
+ struct tipc_shared_handle *h2)
+{
+ return h1->tipc.obj_id == h2->tipc.obj_id &&
+ h1->tipc.size == h2->tipc.size &&
+ h1->tipc.tag == h2->tipc.tag &&
+ h1->dma_buf == h2->dma_buf &&
+ h1->shared == h2->shared;
+}
+
+static bool dma_buf_owns_shared_mem_id(struct tipc_shared_handle *h)
+{
+ /* h->shared is true only if dma_buf did not own an shared memory ID */
+ return !h->shared;
+}
+
static void tipc_shared_handle_register(struct tipc_shared_handle
*new_handle)
{
struct tipc_virtio_dev *vds = new_handle->vds;
- struct rb_node **new = &vds->shared_handles.rb_node;
+ struct rb_node **new;
struct rb_node *parent = NULL;
mutex_lock(&vds->shared_handles_lock);
+ new = &vds->shared_handles.rb_node;
while (*new) {
struct tipc_shared_handle *handle =
rb_entry(*new, struct tipc_shared_handle, node);
parent = *new;
- /* The handle is already registered? */
- if (WARN_ON(handle->tipc.obj_id == new_handle->tipc.obj_id))
- goto already_registered;
+ /*
+ * An obj_id can be registered multiple times if it's owned by a
+ * dma_buf, because in this case we use the same obj_id across
+ * multiple memory transfer operations.
+ */
+ if (handle->tipc.obj_id == new_handle->tipc.obj_id) {
+ if (dma_buf_owns_shared_mem_id(new_handle)) {
+ WARN_ON(!is_same_memory_region(handle,
+ new_handle));
+ } else {
+ WARN(1, "This handle is already registered");
+ goto already_registered;
+ }
+ }
+
if (handle->tipc.obj_id > new_handle->tipc.obj_id)
new = &((*new)->rb_left);
else
@@ -584,11 +623,12 @@ static struct tipc_shared_handle *tipc_shared_handle_take(struct tipc_virtio_dev
trusty_shared_mem_id_t
obj_id)
{
- struct rb_node *node = vds->shared_handles.rb_node;
+ struct rb_node *node;
struct tipc_shared_handle *out = NULL;
mutex_lock(&vds->shared_handles_lock);
+ node = vds->shared_handles.rb_node;
while (node) {
struct tipc_shared_handle *handle =
rb_entry(node, struct tipc_shared_handle, node);
@@ -614,18 +654,23 @@ static int tipc_shared_handle_drop(struct tipc_shared_handle *shared_handle)
struct tipc_virtio_dev *vds = shared_handle->vds;
struct device *dev = tipc_shared_handle_dev(shared_handle);
- /*
- * If this warning fires, it means this shared handle was still in
- * the set of active handles. This shouldn't happen (calling code
- * should ensure it is out if the tree) but this serves as an extra
- * check before it is released.
- *
- * However, the take itself should clean this incorrect state up by
- * removing the handle from the tree.
- */
- WARN_ON(tipc_shared_handle_take(vds, shared_handle->tipc.obj_id));
-
if (shared_handle->shared) {
+ /*
+ * If this warning fires, it means this shared handle was still
+ * in the set of active handles. This shouldn't happen (calling
+ * code should ensure it is out if the tree) but this serves as
+ * an extra check before it is released.
+ *
+ * However, the take itself should clean this incorrect state up
+ * by removing the handle from the tree.
+ *
+ * This warning is only applicable when registering a handle
+ * multiple times is not allowed, i.e. when dma_buf doesn't own
+ * the handle.
+ */
+ WARN_ON(tipc_shared_handle_take(vds,
+ shared_handle->tipc.obj_id));
+
ret = trusty_reclaim_memory(dev,
shared_handle->tipc.obj_id,
shared_handle->sgt->sgl,
@@ -1098,7 +1143,7 @@ static int dn_connect_ioctl(struct tipc_dn_chan *dn, char __user *usr_name)
}
static int dn_share_fd(struct tipc_dn_chan *dn, int fd,
- bool lend,
+ enum transfer_kind transfer_kind,
struct tipc_shared_handle **out)
{
int ret = 0;
@@ -1108,6 +1153,8 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd,
bool writable = false;
pgprot_t prot;
u64 tag = 0;
+ trusty_shared_mem_id_t mem_id;
+ bool lend;
if (dn->state != TIPC_CONNECTED) {
dev_dbg(dev, "Tried to share fd while not connected\n");
@@ -1143,6 +1190,35 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd,
goto cleanup_handle;
}
+ tag = trusty_dma_buf_get_ffa_tag(shared_handle->dma_buf);
+ ret = trusty_dma_buf_get_shared_mem_id(shared_handle->dma_buf, &mem_id);
+ /*
+ * Buffers with a preallocated mem_id should only be sent to Trusty
+ * using TRUSTY_SEND_SECURE. And conversely, TRUSTY_SEND_SECURE should
+ * only be used to send buffers with preallocated mem_id.
+ */
+ if (!ret) {
+ /* Use shared memory ID owned by dma_buf */
+ if (transfer_kind != TRUSTY_SEND_SECURE) {
+ dev_err(dev, "transfer_kind: %d, must be TRUSTY_SEND_SECURE\n",
+ transfer_kind);
+ ret = -EINVAL;
+ goto cleanup_handle;
+ }
+ goto mem_id_allocated;
+ }
+
+ if (ret != -ENODATA) {
+ dev_err(dev, "dma_buf can't be transferred (%d)\n", ret);
+ goto cleanup_handle;
+ }
+
+ if (transfer_kind == TRUSTY_SEND_SECURE) {
+ dev_err(dev, "No mem ID for TRUSTY_SEND_SECURE\n");
+ goto cleanup_handle;
+ }
+ lend = (transfer_kind == TRUSTY_LEND);
+
shared_handle->attach = dma_buf_attach(shared_handle->dma_buf, dev);
if (IS_ERR(shared_handle->attach)) {
ret = PTR_ERR(shared_handle->attach);
@@ -1160,13 +1236,10 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd,
goto cleanup_handle;
}
- tag = trusty_dma_buf_get_ffa_tag(shared_handle->dma_buf);
-
ret = trusty_transfer_memory(tipc_shared_handle_dev(shared_handle),
- &shared_handle->tipc.obj_id,
- shared_handle->sgt->sgl,
- shared_handle->sgt->orig_nents, prot,
- tag, lend);
+ &mem_id, shared_handle->sgt->sgl,
+ shared_handle->sgt->orig_nents, prot, tag,
+ lend);
if (ret < 0) {
dev_dbg(dev, "Transferring memory failed: %d\n", ret);
@@ -1177,6 +1250,9 @@ static int dn_share_fd(struct tipc_dn_chan *dn, int fd,
goto cleanup_handle;
}
shared_handle->shared = true;
+
+mem_id_allocated:
+ shared_handle->tipc.obj_id = mem_id;
shared_handle->tipc.size = shared_handle->dma_buf->size;
shared_handle->tipc.tag = tag;
*out = shared_handle;
@@ -1249,7 +1325,6 @@ static long filp_send_ioctl(struct file *filp,
long ret = 0;
ssize_t data_len = 0;
ssize_t shm_len = 0;
- bool lend = false;
if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT;
@@ -1284,18 +1359,15 @@ static long filp_send_ioctl(struct file *filp,
for (shm_idx = 0; shm_idx < req.shm_cnt; shm_idx++) {
switch (shm[shm_idx].transfer) {
case TRUSTY_SHARE:
- lend = false;
- break;
case TRUSTY_LEND:
- lend = true;
+ case TRUSTY_SEND_SECURE:
break;
default:
dev_err(dev, "Unknown transfer type: 0x%x\n",
shm[shm_idx].transfer);
goto shm_share_failed;
}
- ret = dn_share_fd(dn, shm[shm_idx].fd,
- lend,
+ ret = dn_share_fd(dn, shm[shm_idx].fd, shm[shm_idx].transfer,
&shm_handles[shm_idx]);
if (ret) {
dev_dbg(dev, "Forwarding memory failed\n"
@@ -2186,4 +2258,5 @@ module_exit(tipc_exit);
MODULE_DEVICE_TABLE(tipc, tipc_virtio_id_table);
MODULE_DESCRIPTION("Trusty IPC driver");
+MODULE_IMPORT_NS(DMA_BUF);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c
index 878e589..944d5b0 100644
--- a/drivers/trusty/trusty-log.c
+++ b/drivers/trusty/trusty-log.c
@@ -11,25 +11,57 @@
#include <linux/mm.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/log2.h>
#include <linux/miscdevice.h>
+#include <linux/poll.h>
#include <linux/seq_file.h>
#include <linux/panic_notifier.h>
#include <asm/page.h>
#include "trusty-log.h"
/*
- * Rationale for the chosen log buffer size:
- * - the log buffer shall contain unthrottled trusty crash dump.
- * Testing identifies that the logbuffer size shall be
- * (~96Bytes * 100) i.e. ~2^13
- * - specifying twice as much as the crash dump minimum allows to have
- * ~100 lines of context prior to the crash.
- * - conclusion: logbuffer = 2^14 is comfortable, half is minimal.
+ * Rationale for the chosen default log buffer size:
+ * - the log buffer shall contain unthrottled Trusty crash dump.
+ * - the register list portion of a crash dump is about 1KB
+ * - the memory-around-registers portion of a crash dump can be up to 12 KB
+ * - an average size backtrace is about 1 KB
+ * - average length of non-crash trusty logs during boot is about 85 characters
+ * - a crash dump with 50 lines of context therefore requires up to 18 KB
+ * - buffer size needs to be power-of-two number of bytes
+ * - rounding up to power of two from 18 KB gives 32 KB
+ * The log size can be adjusted by setting the "trusty_log.log_size" parameter
+ * on the kernel command line. The specified value will be adjusted as needed.
*/
-#define TRUSTY_LOG_SIZE (PAGE_SIZE * 5)
-#define TRUSTY_LINE_BUFFER_SIZE 256
+#define TRUSTY_LOG_DEFAULT_SIZE (32768)
+#define TRUSTY_LOG_MIN_SIZE (PAGE_SIZE / 2)
+#define TRUSTY_LOG_MAX_SIZE (1 * 1024 * 1024 * 1024)
+#define TRUSTY_LINE_BUFFER_SIZE (256)
+
+static size_t log_size_param = TRUSTY_LOG_DEFAULT_SIZE;
+
+static int trusty_log_size_set(const char *val, const struct kernel_param *kp)
+{
+ unsigned long long requested = memparse(val, NULL);
+
+ if (requested < TRUSTY_LOG_MIN_SIZE)
+ requested = TRUSTY_LOG_MIN_SIZE;
+ if (requested > TRUSTY_LOG_MAX_SIZE)
+ requested = TRUSTY_LOG_MAX_SIZE;
+ requested = rounddown_pow_of_two(requested);
+ log_size_param = requested;
+ return 0;
+}
+
+static int trusty_log_size_get(char *buffer, const struct kernel_param *kp)
+{
+ sprintf(buffer, "%zu", log_size_param);
+ return strlen(buffer);
+}
+
+module_param_call(log_size, trusty_log_size_set, trusty_log_size_get, NULL,
+ 0644);
/*
* If we log too much and a UART or other slow source is connected, we can stall
* out another thread which is doing printk.
@@ -44,13 +76,11 @@ static struct ratelimit_state trusty_log_rate_limit =
* struct trusty_log_sfile - trusty log misc device state
*
* @misc: misc device created for the trusty log virtual file
- * @sfile: seq_file created when opening the misc device
* @device_name: misc device name following the convention
* "trusty-<name><id>"
*/
struct trusty_log_sfile {
struct miscdevice misc;
- struct seq_file sfile;
char device_name[64];
};
@@ -58,8 +88,6 @@ struct trusty_log_sfile {
* struct trusty_log_sink_state - trusty log sink state
*
* @get: current read unwrapped index
- * @last_successful_next:
- * index for the next line after the last successful get
* @trusty_panicked: trusty panic status at the start of the sink interation
* (only used for kernel log sink)
* @sfile: seq_file used for sinking to a virtual file (misc device);
@@ -76,7 +104,6 @@ struct trusty_log_sfile {
*/
struct trusty_log_sink_state {
u32 get;
- u32 last_successful_next;
bool trusty_panicked;
/* virtual file sink specific attributes */
@@ -89,21 +116,20 @@ struct trusty_log_state {
struct device *trusty_dev;
struct trusty_log_sfile log_sfile;
- /*
- * This lock is here to ensure only one consumer will read
- * from the log ring buffer at a time.
- */
- spinlock_t lock;
struct log_rb *log;
struct trusty_log_sink_state klog_sink;
- struct page *log_pages;
- struct scatterlist sg;
+ u32 log_num_pages;
+ struct scatterlist *sg;
trusty_shared_mem_id_t log_pages_shared_mem_id;
struct notifier_block call_notifier;
struct notifier_block panic_notifier;
char line_buffer[TRUSTY_LINE_BUFFER_SIZE];
+ wait_queue_head_t poll_waiters;
+ /* this lock protects access to wake_put */
+ spinlock_t wake_up_lock;
+ u32 last_wake_put;
};
static inline u32 u32_add_overflow(u32 a, u32 b)
@@ -258,13 +284,10 @@ static void trusty_log_show(struct trusty_log_state *s,
sink->ignore_overflow = false;
if (sink->sfile) {
seq_printf(sink->sfile, "%s", s->line_buffer);
- sink->last_successful_next = sink->get;
} else {
if (sink->trusty_panicked ||
__ratelimit(&trusty_log_rate_limit)) {
dev_info(s->dev, "%s", s->line_buffer);
- /* next line after last successful get */
- sink->last_successful_next = sink->get;
}
}
}
@@ -408,18 +431,13 @@ static int trusty_log_seq_show(struct seq_file *sfile, void *v)
static void trusty_dump_logs(struct trusty_log_state *s)
{
- u32 start;
int rc;
/*
- * note: klopg_sink.get and last_successful_next
- * initialized to zero by kzalloc
+ * note: klog_sink.get initialized to zero by kzalloc
*/
s->klog_sink.trusty_panicked = trusty_get_panic_status(s->trusty_dev);
- start = s->klog_sink.trusty_panicked ?
- s->klog_sink.last_successful_next :
- s->klog_sink.get;
- rc = trusty_log_start(s, &s->klog_sink, start);
+ rc = trusty_log_start(s, &s->klog_sink, s->klog_sink.get);
if (rc < 0)
return;
@@ -432,14 +450,19 @@ static int trusty_log_call_notify(struct notifier_block *nb,
{
struct trusty_log_state *s;
unsigned long flags;
+ u32 cur_put;
if (action != TRUSTY_CALL_RETURNED)
return NOTIFY_DONE;
s = container_of(nb, struct trusty_log_state, call_notifier);
- spin_lock_irqsave(&s->lock, flags);
- trusty_dump_logs(s);
- spin_unlock_irqrestore(&s->lock, flags);
+ spin_lock_irqsave(&s->wake_up_lock, flags);
+ cur_put = s->log->put;
+ if (cur_put != s->last_wake_put) {
+ s->last_wake_put = cur_put;
+ wake_up_all(&s->poll_waiters);
+ }
+ spin_unlock_irqrestore(&s->wake_up_lock, flags);
return NOTIFY_OK;
}
@@ -472,11 +495,19 @@ static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file)
struct seq_file *sfile;
int rc;
+ /*
+ * file->private_data contains a pointer to the misc_device struct
+ * passed to misc_register()
+ */
if (WARN_ON(!file->private_data))
return -EINVAL;
ls = container_of(file->private_data, struct trusty_log_sfile, misc);
+ /*
+ * seq_open uses file->private_data to store the seq_file associated
+ * with the struct file, but it must be NULL when seq_open is called
+ */
file->private_data = NULL;
rc = seq_open(file, &trusty_log_seq_ops);
if (rc < 0)
@@ -490,9 +521,44 @@ static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file)
return 0;
}
+static unsigned int trusty_log_sfile_dev_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct seq_file *sfile;
+ struct trusty_log_sfile *lb;
+ struct trusty_log_state *s;
+ struct log_rb *log;
+
+ /*
+ * trusty_log_sfile_dev_open() pointed filp->private_data to a
+ * seq_file, and that seq_file->private to the trusty_log_sfile
+ * field of a trusty_log_state
+ */
+ sfile = filp->private_data;
+ lb = sfile->private;
+ s = container_of(lb, struct trusty_log_state, log_sfile);
+ poll_wait(filp, &s->poll_waiters, wait);
+ log = s->log;
+
+ /*
+ * Userspace has read up to filp->f_pos so far. Update klog_sink
+ * to indicate that, so that we don't end up dumping the entire
+ * Trusty log in case of panic.
+ */
+ s->klog_sink.get = (u32)filp->f_pos;
+
+ if (log->put != (u32)filp->f_pos) {
+ /* data ready to read */
+ return EPOLLIN | EPOLLRDNORM;
+ }
+ /* no data available, go to sleep */
+ return 0;
+}
+
static const struct file_operations log_sfile_dev_operations = {
.owner = THIS_MODULE,
.open = trusty_log_sfile_dev_open,
+ .poll = trusty_log_sfile_dev_poll,
.read = seq_read,
.release = seq_release,
};
@@ -558,14 +624,15 @@ static bool trusty_supports_logging(struct device *device)
return true;
}
-static int trusty_log_probe(struct platform_device *pdev)
+static int trusty_log_init(struct platform_device *pdev)
{
struct trusty_log_state *s;
+ struct scatterlist *sg;
+ unsigned char *mem;
+ int i;
int result;
trusty_shared_mem_id_t mem_id;
-
- if (!trusty_supports_logging(pdev->dev.parent))
- return -ENXIO;
+ int log_size;
s = kzalloc(sizeof(*s), GFP_KERNEL);
if (!s) {
@@ -573,20 +640,46 @@ static int trusty_log_probe(struct platform_device *pdev)
goto error_alloc_state;
}
- spin_lock_init(&s->lock);
s->dev = &pdev->dev;
s->trusty_dev = s->dev->parent;
- s->log_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO,
- get_order(TRUSTY_LOG_SIZE));
- if (!s->log_pages) {
+
+ s->log_num_pages = DIV_ROUND_UP(log_size_param + sizeof(struct log_rb),
+ PAGE_SIZE);
+ s->sg = kcalloc(s->log_num_pages, sizeof(*s->sg), GFP_KERNEL);
+ if (!s->sg) {
+ result = -ENOMEM;
+ goto error_alloc_sg;
+ }
+
+ log_size = s->log_num_pages * PAGE_SIZE;
+ mem = vzalloc(log_size);
+ if (!mem) {
result = -ENOMEM;
goto error_alloc_log;
}
- s->log = page_address(s->log_pages);
- sg_init_one(&s->sg, s->log, TRUSTY_LOG_SIZE);
- result = trusty_share_memory_compat(s->trusty_dev, &mem_id, &s->sg, 1,
- PAGE_KERNEL);
+ s->log = (struct log_rb *)mem;
+
+ sg_init_table(s->sg, s->log_num_pages);
+ for_each_sg(s->sg, sg, s->log_num_pages, i) {
+ struct page *pg = vmalloc_to_page(mem + (i * PAGE_SIZE));
+
+ if (!pg) {
+ result = -ENOMEM;
+ goto err_share_memory;
+ }
+ sg_set_page(sg, pg, PAGE_SIZE, 0);
+ }
+ /*
+ * This will fail for Trusty api version < TRUSTY_API_VERSION_MEM_OBJ
+ * if s->log_num_pages > 1
+ * Use trusty_share_memory_compat instead of trusty_share_memory in case
+ * s->log_num_pages == 1 and api version < TRUSTY_API_VERSION_MEM_OBJ,
+ * In that case SMC_SC_SHARED_LOG_ADD expects a different value than
+ * what trusty_share_memory returns
+ */
+ result = trusty_share_memory_compat(s->trusty_dev, &mem_id, s->sg,
+ s->log_num_pages, PAGE_KERNEL);
if (result) {
dev_err(s->dev, "trusty_share_memory failed: %d\n", result);
goto err_share_memory;
@@ -596,7 +689,7 @@ static int trusty_log_probe(struct platform_device *pdev)
result = trusty_std_call32(s->trusty_dev,
SMC_SC_SHARED_LOG_ADD,
(u32)(mem_id), (u32)(mem_id >> 32),
- TRUSTY_LOG_SIZE);
+ log_size);
if (result < 0) {
dev_err(s->dev,
"trusty std call (SMC_SC_SHARED_LOG_ADD) failed: %d 0x%llx\n",
@@ -604,6 +697,9 @@ static int trusty_log_probe(struct platform_device *pdev)
goto error_std_call;
}
+ init_waitqueue_head(&s->poll_waiters);
+ spin_lock_init(&s->wake_up_lock);
+
s->call_notifier.notifier_call = trusty_log_call_notify;
result = trusty_call_notifier_register(s->trusty_dev,
&s->call_notifier);
@@ -641,7 +737,8 @@ error_call_notifier:
trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_RM,
(u32)mem_id, (u32)(mem_id >> 32), 0);
error_std_call:
- if (WARN_ON(trusty_reclaim_memory(s->trusty_dev, mem_id, &s->sg, 1))) {
+ if (WARN_ON(trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg,
+ s->log_num_pages))) {
dev_err(&pdev->dev, "trusty_revoke_memory failed: %d 0x%llx\n",
result, mem_id);
/*
@@ -650,14 +747,32 @@ error_std_call:
*/
} else {
err_share_memory:
- __free_pages(s->log_pages, get_order(TRUSTY_LOG_SIZE));
+ vfree(s->log);
}
error_alloc_log:
+ kfree(s->sg);
+error_alloc_sg:
kfree(s);
error_alloc_state:
return result;
}
+static int trusty_log_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ if (!trusty_supports_logging(pdev->dev.parent))
+ return -ENXIO;
+
+ rc = trusty_log_init(pdev);
+ if (rc && log_size_param > TRUSTY_LOG_MIN_SIZE) {
+ dev_warn(&pdev->dev, "init failed, retrying with 1-page log\n");
+ log_size_param = TRUSTY_LOG_MIN_SIZE;
+ rc = trusty_log_init(pdev);
+ }
+ return rc;
+}
+
static int trusty_log_remove(struct platform_device *pdev)
{
int result;
@@ -676,7 +791,8 @@ static int trusty_log_remove(struct platform_device *pdev)
"trusty std call (SMC_SC_SHARED_LOG_RM) failed: %d\n",
result);
}
- result = trusty_reclaim_memory(s->trusty_dev, mem_id, &s->sg, 1);
+ result = trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg,
+ s->log_num_pages);
if (WARN_ON(result)) {
dev_err(&pdev->dev,
"trusty failed to remove shared memory: %d\n", result);
@@ -685,8 +801,9 @@ static int trusty_log_remove(struct platform_device *pdev)
* It is not safe to free this memory if trusty_revoke_memory
* fails. Leak it in that case.
*/
- __free_pages(s->log_pages, get_order(TRUSTY_LOG_SIZE));
+ vfree(s->log);
}
+ kfree(s->sg);
kfree(s);
return 0;
diff --git a/drivers/trusty/trusty-virtio.c b/drivers/trusty/trusty-virtio.c
index fea59cd..8a7eb69 100644
--- a/drivers/trusty/trusty-virtio.c
+++ b/drivers/trusty/trusty-virtio.c
@@ -31,6 +31,8 @@
#define RSC_DESCR_VER 1
struct trusty_vdev;
+static bool use_high_wq;
+module_param(use_high_wq, bool, 0660);
struct trusty_ctx {
struct device *dev;
@@ -45,6 +47,7 @@ struct trusty_ctx {
struct mutex mlock; /* protects vdev_list */
struct workqueue_struct *kick_wq;
struct workqueue_struct *check_wq;
+ struct workqueue_struct *check_wq_high;
};
struct trusty_vring {
@@ -99,7 +102,10 @@ static int trusty_call_notify(struct notifier_block *nb,
return NOTIFY_DONE;
tctx = container_of(nb, struct trusty_ctx, call_notifier);
- queue_work(tctx->check_wq, &tctx->check_vqs);
+ if (use_high_wq)
+ queue_work(tctx->check_wq_high, &tctx->check_vqs);
+ else
+ queue_work(tctx->check_wq, &tctx->check_vqs);
return NOTIFY_OK;
}
@@ -751,6 +757,14 @@ static int trusty_virtio_probe(struct platform_device *pdev)
goto err_create_kick_wq;
}
+ tctx->check_wq_high = alloc_workqueue("trusty-check-wq-high",
+ WQ_UNBOUND | WQ_HIGHPRI, 0);
+ if (!tctx->check_wq_high) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed create trusty-check-wq-high\n");
+ goto err_create_check_wq_high;
+ }
+
ret = trusty_virtio_add_devices(tctx);
if (ret) {
dev_err(&pdev->dev, "Failed to add virtio devices\n");
@@ -761,6 +775,8 @@ static int trusty_virtio_probe(struct platform_device *pdev)
return 0;
err_add_devices:
+ destroy_workqueue(tctx->check_wq_high);
+err_create_check_wq_high:
destroy_workqueue(tctx->kick_wq);
err_create_kick_wq:
destroy_workqueue(tctx->check_wq);
@@ -786,6 +802,7 @@ static int trusty_virtio_remove(struct platform_device *pdev)
/* destroy workqueues */
destroy_workqueue(tctx->kick_wq);
destroy_workqueue(tctx->check_wq);
+ destroy_workqueue(tctx->check_wq_high);
/* notify remote that shared area goes away */
trusty_virtio_stop(tctx, tctx->shared_id, tctx->shared_sz);
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index 265eab5..c773beb 100644
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -24,6 +24,9 @@
struct trusty_state;
static struct platform_driver trusty_driver;
+static bool use_high_wq;
+module_param(use_high_wq, bool, 0660);
+
struct trusty_work {
struct trusty_state *ts;
struct work_struct work;
@@ -38,6 +41,7 @@ struct trusty_state {
bool trusty_panicked;
struct device *dev;
struct workqueue_struct *nop_wq;
+ struct workqueue_struct *nop_wq_high;
struct trusty_work __percpu *nop_works;
struct list_head nop_queue;
spinlock_t nop_lock; /* protects nop_queue */
@@ -753,9 +757,26 @@ static void nop_work_func(struct work_struct *work)
u32 last_arg0;
struct trusty_work *tw = container_of(work, struct trusty_work, work);
struct trusty_state *s = tw->ts;
+ int old_nice = task_nice(current);
+ bool nice_changed = false;
dequeue_nop(s, args);
do {
+ /*
+ * In case use_high_wq flaged when trusty is not idle,
+ * change the work's prio directly.
+ */
+ if (!WARN_ON(current->policy != SCHED_NORMAL)) {
+ if (use_high_wq && task_nice(current) != MIN_NICE) {
+ nice_changed = true;
+ set_user_nice(current, MIN_NICE);
+ } else if (!use_high_wq &&
+ task_nice(current) == MIN_NICE) {
+ nice_changed = true;
+ set_user_nice(current, 0);
+ }
+ }
+
dev_dbg(s->dev, "%s: %x %x %x\n",
__func__, args[0], args[1], args[2]);
@@ -779,7 +800,11 @@ static void nop_work_func(struct work_struct *work)
}
}
} while (next);
-
+ /*
+ * Restore nice if even changed.
+ */
+ if (nice_changed)
+ set_user_nice(current, old_nice);
dev_dbg(s->dev, "%s: done\n", __func__);
}
@@ -799,7 +824,10 @@ void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop)
list_add_tail(&nop->node, &s->nop_queue);
spin_unlock_irqrestore(&s->nop_lock, flags);
}
- queue_work(s->nop_wq, &tw->work);
+ if (use_high_wq)
+ queue_work(s->nop_wq_high, &tw->work);
+ else
+ queue_work(s->nop_wq, &tw->work);
preempt_enable();
}
EXPORT_SYMBOL(trusty_enqueue_nop);
@@ -873,6 +901,14 @@ static int trusty_probe(struct platform_device *pdev)
goto err_create_nop_wq;
}
+ s->nop_wq_high = alloc_workqueue("trusty-nop-wq-high", WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE, 0);
+ if (!s->nop_wq_high) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed create trusty-nop-wq-high\n");
+ goto err_create_nop_wq_high;
+ }
+
s->nop_works = alloc_percpu(struct trusty_work);
if (!s->nop_works) {
ret = -ENOMEM;
@@ -908,6 +944,8 @@ err_add_children:
}
free_percpu(s->nop_works);
err_alloc_works:
+ destroy_workqueue(s->nop_wq_high);
+err_create_nop_wq_high:
destroy_workqueue(s->nop_wq);
err_create_nop_wq:
trusty_free_msg_buf(s, &pdev->dev);
@@ -937,6 +975,7 @@ static int trusty_remove(struct platform_device *pdev)
}
free_percpu(s->nop_works);
destroy_workqueue(s->nop_wq);
+ destroy_workqueue(s->nop_wq_high);
mutex_destroy(&s->share_memory_msg_lock);
mutex_destroy(&s->smc_lock);
diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h
index ec53eb2..efbb369 100644
--- a/include/linux/trusty/trusty.h
+++ b/include/linux/trusty/trusty.h
@@ -85,6 +85,33 @@ static inline u64 trusty_dma_buf_get_ffa_tag(struct dma_buf *dma_buf)
}
#endif
+/* Invalid handle value is defined by FF-A spec */
+#ifdef CONFIG_TRUSTY_DMA_BUF_SHARED_MEM_ID
+/**
+ * trusty_dma_buf_get_shared_mem_id() - Get memory ID corresponding to a dma_buf
+ * @dma_buf: DMA buffer
+ * @id: Pointer to output trusty_shared_mem_id_t
+ *
+ * Sets @id to trusty_shared_mem_id_t corresponding to the given @dma_buf.
+ * @dma_buf "owns" the ID, i.e. is responsible for allocating/releasing it.
+ * @dma_buf with an allocated @id must be in secure memory and should only be
+ * sent to Trusty using TRUSTY_SEND_SECURE.
+ *
+ * Return:
+ * * 0 - success
+ * * -ENODATA - @dma_buf does not own a trusty_shared_mem_id_t
+ * * ... - @dma_buf should not be lent or shared
+ */
+int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf,
+ trusty_shared_mem_id_t *id);
+#else
+static inline int trusty_dma_buf_get_shared_mem_id(struct dma_buf *dma_buf,
+ trusty_shared_mem_id_t *id)
+{
+ return -ENODATA;
+}
+#endif
+
struct trusty_nop {
struct list_head node;
u32 args[3];
diff --git a/include/uapi/linux/trusty/ipc.h b/include/uapi/linux/trusty/ipc.h
index 20cdd90..af91035 100644
--- a/include/uapi/linux/trusty/ipc.h
+++ b/include/uapi/linux/trusty/ipc.h
@@ -9,15 +9,19 @@
/**
* enum transfer_kind - How to send an fd to Trusty
- * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will
- * be mapped as nonsecure. Suitable for shared memory. The paired
- * fd must be a "memfd".
- * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will be
- * transitioned to "Secure" memory if Trusty is in TrustZone.
- * This transfer kind is suitable for donating video buffers or
- * other similar resources. The paired fd may need to come from a
- * platform-specific allocator for memory that may be
- * transitioned to "Secure".
+ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it
+ * will be mapped as nonsecure. Suitable for shared memory.
+ * The paired fd must be a "dma_buf".
+ * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will
+ * be transitioned to "Secure" memory if Trusty is in
+ * TrustZone. This transfer kind is suitable for donating
+ * video buffers or other similar resources. The paired fd
+ * may need to come from a platform-specific allocator for
+ * memory that may be transitioned to "Secure".
+ * @TRUSTY_SEND_SECURE: Send memory that is already "Secure". Memory will be
+ * accessible only to Trusty. The paired fd may need to
+ * come from a platform-specific allocator that returns
+ * "Secure" buffers.
*
* Describes how the user would like the resource in question to be sent to
* Trusty. Options may be valid only for certain kinds of fds.
@@ -25,6 +29,7 @@
enum transfer_kind {
TRUSTY_SHARE = 0,
TRUSTY_LEND = 1,
+ TRUSTY_SEND_SECURE = 2,
};
/**