summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/channel.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/channel.c131
1 files changed, 130 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/channel.c b/drivers/gpu/nvgpu/common/linux/channel.c
index 8366ed88..1ae2d444 100644
--- a/drivers/gpu/nvgpu/common/linux/channel.c
+++ b/drivers/gpu/nvgpu/common/linux/channel.c
@@ -17,6 +17,7 @@
17#include <nvgpu/enabled.h> 17#include <nvgpu/enabled.h>
18#include <nvgpu/debug.h> 18#include <nvgpu/debug.h>
19#include <nvgpu/ltc.h> 19#include <nvgpu/ltc.h>
20#include <nvgpu/error_notifier.h>
20 21
21/* 22/*
22 * This is required for nvgpu_vm_find_buf() which is used in the tracing 23 * This is required for nvgpu_vm_find_buf() which is used in the tracing
@@ -37,6 +38,124 @@
37#include <trace/events/gk20a.h> 38#include <trace/events/gk20a.h>
38#include <uapi/linux/nvgpu.h> 39#include <uapi/linux/nvgpu.h>
39 40
41/*
42 * API to convert error_notifiers in common code and of the form
43 * NVGPU_ERR_NOTIFIER_* into Linux specific error_notifiers exposed to user
44 * space and of the form NVGPU_CHANNEL_*
45 */
46static u32 nvgpu_error_notifier_to_channel_notifier(u32 error_notifier)
47{
48 switch (error_notifier) {
49 case NVGPU_ERR_NOTIFIER_FIFO_ERROR_IDLE_TIMEOUT:
50 return NVGPU_CHANNEL_FIFO_ERROR_IDLE_TIMEOUT;
51 case NVGPU_ERR_NOTIFIER_GR_ERROR_SW_METHOD:
52 return NVGPU_CHANNEL_GR_ERROR_SW_METHOD;
53 case NVGPU_ERR_NOTIFIER_GR_ERROR_SW_NOTIFY:
54 return NVGPU_CHANNEL_GR_ERROR_SW_NOTIFY;
55 case NVGPU_ERR_NOTIFIER_GR_EXCEPTION:
56 return NVGPU_CHANNEL_GR_EXCEPTION;
57 case NVGPU_ERR_NOTIFIER_GR_SEMAPHORE_TIMEOUT:
58 return NVGPU_CHANNEL_GR_SEMAPHORE_TIMEOUT;
59 case NVGPU_ERR_NOTIFIER_GR_ILLEGAL_NOTIFY:
60 return NVGPU_CHANNEL_GR_ILLEGAL_NOTIFY;
61 case NVGPU_ERR_NOTIFIER_FIFO_ERROR_MMU_ERR_FLT:
62 return NVGPU_CHANNEL_FIFO_ERROR_MMU_ERR_FLT;
63 case NVGPU_ERR_NOTIFIER_PBDMA_ERROR:
64 return NVGPU_CHANNEL_PBDMA_ERROR;
65 case NVGPU_ERR_NOTIFIER_FECS_ERR_UNIMP_FIRMWARE_METHOD:
66 return NVGPU_CHANNEL_FECS_ERR_UNIMP_FIRMWARE_METHOD;
67 case NVGPU_ERR_NOTIFIER_RESETCHANNEL_VERIF_ERROR:
68 return NVGPU_CHANNEL_RESETCHANNEL_VERIF_ERROR;
69 case NVGPU_ERR_NOTIFIER_PBDMA_PUSHBUFFER_CRC_MISMATCH:
70 return NVGPU_CHANNEL_PBDMA_PUSHBUFFER_CRC_MISMATCH;
71 }
72
73 pr_warn("%s: invalid error_notifier requested %u\n", __func__, error_notifier);
74
75 return error_notifier;
76}
77
78/**
79 * nvgpu_set_error_notifier_locked()
80 * Should be called with ch->error_notifier_mutex held
81 *
82 * error should be of the form NVGPU_ERR_NOTIFIER_*
83 */
84void nvgpu_set_error_notifier_locked(struct channel_gk20a *ch, u32 error)
85{
86 struct nvgpu_channel_linux *priv = ch->os_priv;
87
88 error = nvgpu_error_notifier_to_channel_notifier(error);
89
90 if (priv->error_notifier.dmabuf) {
91 struct nvgpu_notification *notification =
92 priv->error_notifier.notification;
93 struct timespec time_data;
94 u64 nsec;
95
96 getnstimeofday(&time_data);
97 nsec = ((u64)time_data.tv_sec) * 1000000000u +
98 (u64)time_data.tv_nsec;
99 notification->time_stamp.nanoseconds[0] =
100 (u32)nsec;
101 notification->time_stamp.nanoseconds[1] =
102 (u32)(nsec >> 32);
103 notification->info32 = error;
104 notification->status = 0xffff;
105
106 nvgpu_err(ch->g,
107 "error notifier set to %d for ch %d", error, ch->chid);
108 }
109}
110
111/* error should be of the form NVGPU_ERR_NOTIFIER_* */
112void nvgpu_set_error_notifier(struct channel_gk20a *ch, u32 error)
113{
114 struct nvgpu_channel_linux *priv = ch->os_priv;
115
116 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
117 nvgpu_set_error_notifier_locked(ch, error);
118 nvgpu_mutex_release(&priv->error_notifier.mutex);
119}
120
121void nvgpu_set_error_notifier_if_empty(struct channel_gk20a *ch, u32 error)
122{
123 struct nvgpu_channel_linux *priv = ch->os_priv;
124
125 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
126 if (priv->error_notifier.dmabuf) {
127 struct nvgpu_notification *notification =
128 priv->error_notifier.notification;
129
130 /* Don't overwrite error flag if it is already set */
131 if (notification->status != 0xffff)
132 nvgpu_set_error_notifier_locked(ch, error);
133 }
134 nvgpu_mutex_release(&priv->error_notifier.mutex);
135}
136
137/* error_notifier should be of the form NVGPU_ERR_NOTIFIER_* */
138bool nvgpu_is_error_notifier_set(struct channel_gk20a *ch, u32 error_notifier)
139{
140 struct nvgpu_channel_linux *priv = ch->os_priv;
141 bool notifier_set = false;
142
143 error_notifier = nvgpu_error_notifier_to_channel_notifier(error_notifier);
144
145 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
146 if (priv->error_notifier.dmabuf) {
147 struct nvgpu_notification *notification =
148 priv->error_notifier.notification;
149 u32 err = notification->info32;
150
151 if (err == error_notifier)
152 notifier_set = true;
153 }
154 nvgpu_mutex_release(&priv->error_notifier.mutex);
155
156 return notifier_set;
157}
158
40static void gk20a_channel_update_runcb_fn(struct work_struct *work) 159static void gk20a_channel_update_runcb_fn(struct work_struct *work)
41{ 160{
42 struct nvgpu_channel_completion_cb *completion_cb = 161 struct nvgpu_channel_completion_cb *completion_cb =
@@ -128,6 +247,7 @@ static void nvgpu_channel_close_linux(struct channel_gk20a *ch)
128static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch) 247static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch)
129{ 248{
130 struct nvgpu_channel_linux *priv; 249 struct nvgpu_channel_linux *priv;
250 int err;
131 251
132 priv = nvgpu_kzalloc(g, sizeof(*priv)); 252 priv = nvgpu_kzalloc(g, sizeof(*priv));
133 if (!priv) 253 if (!priv)
@@ -136,6 +256,12 @@ static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch)
136 ch->os_priv = priv; 256 ch->os_priv = priv;
137 priv->ch = ch; 257 priv->ch = ch;
138 258
259 err = nvgpu_mutex_init(&priv->error_notifier.mutex);
260 if (err) {
261 nvgpu_kfree(g, priv);
262 return err;
263 }
264
139 nvgpu_channel_work_completion_init(ch); 265 nvgpu_channel_work_completion_init(ch);
140 266
141 return 0; 267 return 0;
@@ -143,7 +269,10 @@ static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch)
143 269
144static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch) 270static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch)
145{ 271{
146 nvgpu_kfree(g, ch->os_priv); 272 struct nvgpu_channel_linux *priv = ch->os_priv;
273
274 nvgpu_mutex_destroy(&priv->error_notifier.mutex);
275 nvgpu_kfree(g, priv);
147} 276}
148 277
149int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) 278int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l)