Files
linux-nvgpu/drivers/gpu/nvgpu/gk20a/ce2_gk20a.c
Deepak Nibade db8bce518b gpu: nvgpu: wakeup semaphores after clearing CE2 interrupt
In gk20a_ce2_nonstall_isr(), we first invoke semaphore workqueue
on all channels and then clear the interrupt
This delay in clearing the interrupt can sometimes lead to
dropping of new interrupt

If that happens, we never invoke gk20a_channel_semaphore_wakeup()
for new semaphore interrupts and semaphore waiting
never completes.

Fix this by moving gk20a_channel_semaphore_wakeup() after
we clear the interrupt

Bug 200131938

Change-Id: I26d72f04a8b49f4a3ac326bf6037cd04c741a920
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/784771
Reviewed-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-by: Seshendra Gadagottu <sgadagottu@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
2015-08-18 13:53:54 -07:00

100 lines
2.8 KiB
C

/*
* GK20A Graphics Copy Engine (gr host)
*
* Copyright (c) 2011-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,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*TODO: remove uncecessary */
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <trace/events/gk20a.h>
#include <linux/dma-mapping.h>
#include <linux/nvhost.h>
#include "gk20a.h"
#include "debug_gk20a.h"
#include "semaphore_gk20a.h"
#include "hw_ce2_gk20a.h"
#include "hw_pbdma_gk20a.h"
#include "hw_ccsr_gk20a.h"
#include "hw_ram_gk20a.h"
#include "hw_proj_gk20a.h"
#include "hw_top_gk20a.h"
#include "hw_mc_gk20a.h"
#include "hw_gr_gk20a.h"
static u32 ce2_nonblockpipe_isr(struct gk20a *g, u32 fifo_intr)
{
gk20a_dbg(gpu_dbg_intr, "ce2 non-blocking pipe interrupt\n");
return ce2_intr_status_nonblockpipe_pending_f();
}
static u32 ce2_blockpipe_isr(struct gk20a *g, u32 fifo_intr)
{
gk20a_dbg(gpu_dbg_intr, "ce2 blocking pipe interrupt\n");
return ce2_intr_status_blockpipe_pending_f();
}
static u32 ce2_launcherr_isr(struct gk20a *g, u32 fifo_intr)
{
gk20a_dbg(gpu_dbg_intr, "ce2 launch error interrupt\n");
return ce2_intr_status_launcherr_pending_f();
}
void gk20a_ce2_isr(struct gk20a *g)
{
u32 ce2_intr = gk20a_readl(g, ce2_intr_status_r());
u32 clear_intr = 0;
gk20a_dbg(gpu_dbg_intr, "ce2 isr %08x\n", ce2_intr);
/* clear blocking interrupts: they exibit broken behavior */
if (ce2_intr & ce2_intr_status_blockpipe_pending_f())
clear_intr |= ce2_blockpipe_isr(g, ce2_intr);
if (ce2_intr & ce2_intr_status_launcherr_pending_f())
clear_intr |= ce2_launcherr_isr(g, ce2_intr);
gk20a_writel(g, ce2_intr_status_r(), clear_intr);
return;
}
void gk20a_ce2_nonstall_isr(struct gk20a *g)
{
u32 ce2_intr = gk20a_readl(g, ce2_intr_status_r());
gk20a_dbg(gpu_dbg_intr, "ce2 nonstall isr %08x\n", ce2_intr);
if (ce2_intr & ce2_intr_status_nonblockpipe_pending_f()) {
gk20a_writel(g, ce2_intr_status_r(),
ce2_nonblockpipe_isr(g, ce2_intr));
/* wake threads waiting in this channel */
gk20a_channel_semaphore_wakeup(g);
}
return;
}
void gk20a_init_ce2(struct gpu_ops *gops)
{
gops->ce2.isr_stall = gk20a_ce2_isr;
gops->ce2.isr_nonstall = gk20a_ce2_nonstall_isr;
}