From 983d45ff7158b5ff7f296b95a727b3bb49641f85 Mon Sep 17 00:00:00 2001 From: Aingara Paramakuru Date: Tue, 6 Jan 2015 16:22:52 -0500 Subject: [PATCH] video: tegra: virt: switch to IVC IRQ Handling IVC notifications using the callback method is problematic when trying to handle the IVC reset protocol. The comm framework now handles IVC IRQs locally. Bug 1566409 Change-Id: I969500dd5599efb15a49ee44a79a7872ecc48e58 Signed-off-by: Aingara Paramakuru Reviewed-on: http://git-master/r/671865 Reviewed-on: http://git-master/r/1198216 Reviewed-on: http://git-master/r/1314830 GVS: Gerrit_Virtual_Submit Reviewed-by: Aniruddha Banerjee Tested-by: Aniruddha Banerjee Reviewed-by: Timo Alho --- drivers/video/tegra/virt/tegra_gr_comm.c | 144 ++++++++--------------- 1 file changed, 47 insertions(+), 97 deletions(-) diff --git a/drivers/video/tegra/virt/tegra_gr_comm.c b/drivers/video/tegra/virt/tegra_gr_comm.c index 4c1a7f4b..c98b2046 100644 --- a/drivers/video/tegra/virt/tegra_gr_comm.c +++ b/drivers/video/tegra/virt/tegra_gr_comm.c @@ -1,7 +1,7 @@ /* * Tegra Graphics Virtualization Communication Framework * - * Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2013-2015, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -29,46 +29,33 @@ #include #include #include +#include #include #include #define NUM_QUEUES 4 #define NUM_CONTEXTS 2 -#define ID_SHIFT 11 -#define ID_MASK 1 -#define ID0_PEER_ID_SHIFT 4 -#define ID0_QUEUE_ID_SHIFT 1 -#define ID0_QUEUE_ID_MASK 7 -#define ID0_VCTX_SHIFT 0 -#define ID0_VCTX_MASK 1 -#define ID1_IRQ_SHIFT 0 +#define ID_PEER_ID_SHIFT 4 +#define ID_QUEUE_ID_SHIFT 1 +#define ID_QUEUE_ID_MASK 7 +#define ID_VCTX_SHIFT 0 +#define ID_VCTX_MASK 1 -#define GEN_ID0(vctx, queue_id, peer_id) \ - ((peer_id << ID0_PEER_ID_SHIFT) | \ - (queue_id << ID0_QUEUE_ID_SHIFT) | \ - (vctx << ID0_VCTX_SHIFT) | \ - (0 << ID_SHIFT)) -#define GEN_ID1(irq) \ - ((irq << ID1_IRQ_SHIFT) | \ - (1 << ID_SHIFT)) -#define IS_ID1(id) ((id >> ID_SHIFT) & ID_MASK) -#define VCTX_FROM_ID0(id) ((id >> ID0_VCTX_SHIFT) & ID0_VCTX_MASK) -#define QUEUE_ID_FROM_ID0(id) ((id >> ID0_QUEUE_ID_SHIFT) & ID0_QUEUE_ID_MASK) - -enum { - IVC_DIR_TX = 0, - IVC_DIR_RX, - NUM_IVC_DIR -}; +#define GEN_ID(vctx, queue_id, peer_id) \ + ((peer_id << ID_PEER_ID_SHIFT) | \ + (queue_id << ID_QUEUE_ID_SHIFT) | \ + (vctx << ID_VCTX_SHIFT)) +#define VCTX_FROM_ID(id) ((id >> ID_VCTX_SHIFT) & ID_VCTX_MASK) +#define QUEUE_ID_FROM_ID(id) ((id >> ID_QUEUE_ID_SHIFT) & ID_QUEUE_ID_MASK) struct gr_comm_ivc_context { u32 peer; - wait_queue_head_t wq[NUM_IVC_DIR]; + wait_queue_head_t wq; struct tegra_hv_ivc_cookie *cookie; struct gr_comm_queue *queue; - struct task_struct *rx_thread; struct platform_device *pdev; + bool irq_requested; }; struct gr_comm_element { @@ -115,47 +102,20 @@ static void free_ivc(u32 virt_ctx, u32 queue_start, u32 queue_end) int id; idr_for_each_entry(&ivc_ctx_idr, tmp, id) { - if (VCTX_FROM_ID0(id) == virt_ctx && - QUEUE_ID_FROM_ID0(id) >= queue_start && - QUEUE_ID_FROM_ID0(id) < queue_end) { + if (VCTX_FROM_ID(id) == virt_ctx && + QUEUE_ID_FROM_ID(id) >= queue_start && + QUEUE_ID_FROM_ID(id) < queue_end) { idr_remove(&ivc_ctx_idr, id); - if (tmp->rx_thread) - kthread_stop(tmp->rx_thread); + if (tmp->irq_requested) + free_irq(tmp->cookie->irq, tmp); - if (tmp->cookie) { - idr_remove(&ivc_ctx_idr, - GEN_ID1(tmp->cookie->irq)); + if (tmp->cookie) tegra_hv_ivc_unreserve(tmp->cookie); - } kfree(tmp); } } } -static void ivc_rx(struct tegra_hv_ivc_cookie *ivck) -{ - struct gr_comm_ivc_context *ctx = - idr_find(&ivc_ctx_idr, GEN_ID1(ivck->irq)); - - if (!ctx) - return; - - wake_up(&ctx->wq[IVC_DIR_RX]); -} - -static void ivc_tx(struct tegra_hv_ivc_cookie *ivck) -{ - struct gr_comm_ivc_context *ctx = - idr_find(&ivc_ctx_idr, GEN_ID1(ivck->irq)); - - if (!ctx) - return; - - wake_up(&ctx->wq[IVC_DIR_TX]); -} - -static const struct tegra_hv_ivc_ops ivc_ops = { ivc_rx, ivc_tx }; - static int queue_add(struct gr_comm_queue *queue, const char *data, u32 peer, struct tegra_hv_ivc_cookie *ivck) { @@ -194,32 +154,27 @@ static int queue_add(struct gr_comm_queue *queue, const char *data, return 0; } -static int ivc_rx_thread(void *arg) +static irqreturn_t ivc_intr_isr(int irq, void *dev_id) { - struct gr_comm_ivc_context *ctx = (struct gr_comm_ivc_context *)arg; + return IRQ_WAKE_THREAD; +} + +static irqreturn_t ivc_intr_thread(int irq, void *dev_id) +{ + struct gr_comm_ivc_context *ctx = dev_id; struct device *dev = &ctx->pdev->dev; - int ret; - - while (!kthread_should_stop()) { - if (!tegra_hv_ivc_can_read(ctx->cookie)) { - ret = wait_event_timeout(ctx->wq[IVC_DIR_RX], - tegra_hv_ivc_can_read(ctx->cookie) || - kthread_should_stop(), - msecs_to_jiffies(250)); - - if (kthread_should_stop()) - break; - else if (!ret) - continue; - } + while (tegra_hv_ivc_can_read(ctx->cookie)) { if (queue_add(ctx->queue, NULL, ctx->peer, ctx->cookie)) { dev_err(dev, "%s cannot add to queue\n", __func__); - continue; + break; } } - return 0; + if (tegra_hv_ivc_can_write(ctx->cookie)) + wake_up(&ctx->wq); + + return IRQ_HANDLED; } static int setup_ivc(u32 virt_ctx, struct platform_device *pdev, @@ -241,7 +196,6 @@ static int setup_ivc(u32 virt_ctx, struct platform_device *pdev, struct gr_comm_ivc_context *ctx; struct gr_comm_queue *queue = &contexts[virt_ctx].queue[i]; - char thread_name[30]; int id, err; hv_dn = of_parse_phandle(dev->of_node, name, @@ -257,11 +211,10 @@ static int setup_ivc(u32 virt_ctx, struct platform_device *pdev, ctx->pdev = pdev; ctx->queue = queue; - init_waitqueue_head(&ctx->wq[IVC_DIR_TX]); - init_waitqueue_head(&ctx->wq[IVC_DIR_RX]); + init_waitqueue_head(&ctx->wq); ctx->cookie = - tegra_hv_ivc_reserve(hv_dn, inst, &ivc_ops); + tegra_hv_ivc_reserve(hv_dn, inst, NULL); if (IS_ERR_OR_NULL(ctx->cookie)) { ret = PTR_ERR(ctx->cookie); kfree(ctx); @@ -277,7 +230,7 @@ static int setup_ivc(u32 virt_ctx, struct platform_device *pdev, ctx->peer = ctx->cookie->peer_vmid; - id = GEN_ID0(virt_ctx, i, ctx->peer); + id = GEN_ID(virt_ctx, i, ctx->peer); err = idr_alloc(&ivc_ctx_idr, ctx, id, id + 1, GFP_KERNEL); if (err != id) { @@ -286,19 +239,16 @@ static int setup_ivc(u32 virt_ctx, struct platform_device *pdev, goto fail; } - id = GEN_ID1(ctx->cookie->irq); - err = idr_alloc(&ivc_ctx_idr, ctx, id, id + 1, - GFP_KERNEL); - if (err != id) - goto fail; - server_vmid = ctx->peer; - snprintf(thread_name, sizeof(thread_name), - "gr-virt-thr-%d-%d-%d", virt_ctx, i, ctx->peer); - ctx->rx_thread = - kthread_run(ivc_rx_thread, ctx, thread_name); - if (IS_ERR(ctx->rx_thread)) + err = request_threaded_irq(ctx->cookie->irq, + ivc_intr_isr, + ivc_intr_thread, + 0, "gr-virt", ctx); + if (err) { + ret = -ENOMEM; goto fail; + } + ctx->irq_requested = true; } if (j == 0) goto fail; @@ -445,12 +395,12 @@ int tegra_gr_comm_send(u32 virt_ctx, u32 peer, u32 index, void *data, if (peer == TEGRA_GR_COMM_ID_SELF) return queue_add(&ctx->queue[index], data, peer, NULL); - ivc_ctx = idr_find(&ivc_ctx_idr, GEN_ID0(virt_ctx, index, peer)); + ivc_ctx = idr_find(&ivc_ctx_idr, GEN_ID(virt_ctx, index, peer)); if (!ivc_ctx) return -EINVAL; if (!tegra_hv_ivc_can_write(ivc_ctx->cookie)) { - ret = wait_event_timeout(ivc_ctx->wq[IVC_DIR_TX], + ret = wait_event_timeout(ivc_ctx->wq, tegra_hv_ivc_can_write(ivc_ctx->cookie), msecs_to_jiffies(250)); if (!ret) {