diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/channel.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/channel.c | 131 |
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 | */ | ||
46 | static 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 | */ | ||
84 | void 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_* */ | ||
112 | void 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 | |||
121 | void 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_* */ | ||
138 | bool 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 | |||
40 | static void gk20a_channel_update_runcb_fn(struct work_struct *work) | 159 | static 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) | |||
128 | static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch) | 247 | static 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 | ||
144 | static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch) | 270 | static 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 | ||
149 | int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) | 278 | int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) |