aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/4151-drm-amdkfd-Simplify-dGPU-event-page-allocation.patch
blob: d279476703608712816842137bca794865b77305 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
From 25edfba75db6c5455606aa0e626c427c7e2477dd Mon Sep 17 00:00:00 2001
From: Felix Kuehling <Felix.Kuehling@amd.com>
Date: Mon, 19 Mar 2018 18:02:07 -0400
Subject: [PATCH 4151/5725] drm/amdkfd: Simplify dGPU event page allocation

Deal with all the events page allocation in kfd_chardev.c and remove
unnecessary checks for APU. This will also potentially allow mixed
configurations of dGPUs with APUs.

Explicitly set the events page in the ioctl instead of doing it
implicitly in kfd_event_create. This also fixes a potential memory
leak if the events page was already set in a previous call. This
will now fail.

Explicitly remember how the events page was allocated so it can be
freed correctly.

Change-Id: I77ecd0b699c20d2e9a1ff7226e387df143ad6a5b
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
---
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 84 +++++++++++++++++++-------------
 drivers/gpu/drm/amd/amdkfd/kfd_events.c  | 69 +++++++++++---------------
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h    |  4 +-
 3 files changed, 80 insertions(+), 77 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 0c89373..c5e6488 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -976,55 +976,69 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p,
 					void *data)
 {
 	struct kfd_ioctl_create_event_args *args = data;
-	struct kfd_dev *kfd;
-	struct kfd_process_device *pdd;
-	int err = -EINVAL;
-	void *mem, *kern_addr = NULL;
-
-	pr_debug("Event page offset 0x%llx\n", args->event_page_offset);
+	int err;
 
+	/* For dGPUs the event page is allocated in user mode. The
+	 * handle is passed to KFD with the first call to this IOCTL
+	 * through the event_page_offset field.
+	 */
 	if (args->event_page_offset) {
+		struct kfd_dev *kfd;
+		struct kfd_process_device *pdd;
+		void *mem, *kern_addr;
+
+		if (p->signal_page) {
+			pr_err("Event page is already set\n");
+			return -EINVAL;
+		}
+
 		kfd = kfd_device_by_id(GET_GPU_ID(args->event_page_offset));
 		if (!kfd) {
 			pr_err("Getting device by id failed in %s\n", __func__);
-			return -EFAULT;
+			return -EINVAL;
 		}
-		if (!kfd->device_info->needs_iommu_device) {
-			mutex_lock(&p->mutex);
-			pdd = kfd_bind_process_to_device(kfd, p);
-			if (IS_ERR(pdd)) {
-				err = PTR_ERR(pdd);
-				goto out_upwrite;
-			}
-			mem = kfd_process_device_translate_handle(pdd,
+
+		mutex_lock(&p->mutex);
+		pdd = kfd_bind_process_to_device(kfd, p);
+		if (IS_ERR(pdd)) {
+			err = PTR_ERR(pdd);
+			goto out_unlock;
+		}
+
+		mem = kfd_process_device_translate_handle(pdd,
 				GET_IDR_HANDLE(args->event_page_offset));
-			if (!mem) {
-				pr_err("Can't find BO, offset is 0x%llx\n",
-						args->event_page_offset);
-				err = -EFAULT;
-				goto out_upwrite;
-			}
-			mutex_unlock(&p->mutex);
+		if (!mem) {
+			pr_err("Can't find BO, offset is 0x%llx\n",
+			       args->event_page_offset);
+			err = -EINVAL;
+			goto out_unlock;
+		}
+		mutex_unlock(&p->mutex);
 
-			/* Map dGPU gtt BO to kernel */
-			kfd->kfd2kgd->map_gtt_bo_to_kernel(kfd->kgd,
-					mem, &kern_addr, NULL);
+		err = kfd->kfd2kgd->map_gtt_bo_to_kernel(kfd->kgd,
+						mem, &kern_addr, NULL);
+		if (err) {
+			pr_err("Failed to map event page to kernel\n");
+			return err;
+		}
+
+		err = kfd_event_page_set(p, kern_addr);
+		if (err) {
+			pr_err("Failed to set event page\n");
+			return err;
 		}
 	}
 
-	err = kfd_event_create(filp, p,
-			args->event_type,
-			args->auto_reset != 0,
-			args->node_id,
-			&args->event_id,
-			&args->event_trigger_data,
-			&args->event_page_offset,
-			&args->event_slot_index,
-			kern_addr);
+
+	err = kfd_event_create(filp, p, args->event_type,
+				args->auto_reset != 0, args->node_id,
+				&args->event_id, &args->event_trigger_data,
+				&args->event_page_offset,
+				&args->event_slot_index);
 
 	return err;
 
-out_upwrite:
+out_unlock:
 	mutex_unlock(&p->mutex);
 	return err;
 }
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index a92ca78..d002016 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -51,8 +51,8 @@ struct kfd_event_waiter {
  */
 struct kfd_signal_page {
 	uint64_t *kernel_address;
-	uint64_t handle;
 	uint64_t __user *user_address;
+	bool need_to_free_pages;
 };
 
 
@@ -80,6 +80,7 @@ static struct kfd_signal_page *allocate_signal_page(struct kfd_process *p)
 	       KFD_SIGNAL_EVENT_LIMIT * 8);
 
 	page->kernel_address = backing_store;
+	page->need_to_free_pages = true;
 	pr_debug("Allocated new event signal page at %p, for process %p\n",
 			page, p);
 
@@ -112,29 +113,6 @@ static int allocate_event_notification_slot(struct kfd_process *p,
 	return 0;
 }
 
-static struct kfd_signal_page *allocate_signal_page_dgpu(
-	struct kfd_process *p, uint64_t *kernel_address, uint64_t handle)
-{
-	struct kfd_signal_page *my_page;
-
-	my_page = kzalloc(sizeof(*my_page), GFP_KERNEL);
-	if (!my_page)
-		return NULL;
-
-	/* Initialize all events to unsignaled */
-	memset(kernel_address, (uint8_t) UNSIGNALED_EVENT_SLOT,
-	       KFD_SIGNAL_EVENT_LIMIT * 8);
-
-	my_page->kernel_address = kernel_address;
-	my_page->handle = handle;
-	my_page->user_address = NULL;
-
-	pr_debug("Allocated new event signal page at %p, for process %p\n",
-			my_page, p);
-
-	return my_page;
-}
-
 /*
  * Assumes that p->event_mutex is held and of course that p is not going
  * away (current or locked).
@@ -284,9 +262,9 @@ static void shutdown_signal_page(struct kfd_process *p)
 	struct kfd_signal_page *page = p->signal_page;
 
 	if (page) {
-		if (page->user_address)
+		if (page->need_to_free_pages)
 			free_pages((unsigned long)page->kernel_address,
-					get_order(KFD_SIGNAL_EVENT_LIMIT * 8));
+				   get_order(KFD_SIGNAL_EVENT_LIMIT * 8));
 		kfree(page);
 	}
 }
@@ -308,11 +286,32 @@ static bool event_can_be_cpu_signaled(const struct kfd_event *ev)
 	return ev->type == KFD_EVENT_TYPE_SIGNAL;
 }
 
+int kfd_event_page_set(struct kfd_process *p, void *kernel_address)
+{
+	struct kfd_signal_page *page;
+
+	if (p->signal_page)
+		return -EBUSY;
+
+	page = kzalloc(sizeof(*page), GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	/* Initialize all events to unsignaled */
+	memset(kernel_address, (uint8_t) UNSIGNALED_EVENT_SLOT,
+	       KFD_SIGNAL_EVENT_LIMIT * 8);
+
+	page->kernel_address = kernel_address;
+
+	p->signal_page = page;
+
+	return 0;
+}
+
 int kfd_event_create(struct file *devkfd, struct kfd_process *p,
 		     uint32_t event_type, bool auto_reset, uint32_t node_id,
 		     uint32_t *event_id, uint32_t *event_trigger_data,
-		     uint64_t *event_page_offset, uint32_t *event_slot_index,
-		     void *kern_addr)
+		     uint64_t *event_page_offset, uint32_t *event_slot_index)
 {
 	int ret = 0;
 	struct kfd_event *ev = kzalloc(sizeof(*ev), GFP_KERNEL);
@@ -326,19 +325,10 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p,
 
 	init_waitqueue_head(&ev->wq);
 
-	mutex_lock(&p->event_mutex);
-
-	if (kern_addr && !p->signal_page) {
-		p->signal_page = allocate_signal_page_dgpu(p, kern_addr,
-							   *event_page_offset);
-		if (!p->signal_page) {
-			ret = -ENOMEM;
-			goto out;
-		}
-	}
-
 	*event_page_offset = 0;
 
+	mutex_lock(&p->event_mutex);
+
 	switch (event_type) {
 	case KFD_EVENT_TYPE_SIGNAL:
 	case KFD_EVENT_TYPE_DEBUG:
@@ -361,7 +351,6 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p,
 		kfree(ev);
 	}
 
-out:
 	mutex_unlock(&p->event_mutex);
 
 	return ret;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index b2ef0f5..5928080 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -1056,11 +1056,11 @@ void kfd_signal_iommu_event(struct kfd_dev *dev,
 void kfd_signal_hw_exception_event(unsigned int pasid);
 int kfd_set_event(struct kfd_process *p, uint32_t event_id);
 int kfd_reset_event(struct kfd_process *p, uint32_t event_id);
+int kfd_event_page_set(struct kfd_process *p, void *kernel_address);
 int kfd_event_create(struct file *devkfd, struct kfd_process *p,
 		     uint32_t event_type, bool auto_reset, uint32_t node_id,
 		     uint32_t *event_id, uint32_t *event_trigger_data,
-		     uint64_t *event_page_offset, uint32_t *event_slot_index,
-		     void *kern_addr);
+		     uint64_t *event_page_offset, uint32_t *event_slot_index);
 int kfd_event_destroy(struct kfd_process *p, uint32_t event_id);
 
 void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid,
-- 
2.7.4