aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOded Gabbay <oded.gabbay@gmail.com>2019-02-15 17:39:17 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-02-18 03:46:45 -0500
commit9494a8dd8d22cbff8ce358aaa223fffe1b070cb0 (patch)
tree8a7b51e6440aa5248026140fa33d42172dde26de
parent839c48030d27a690cc85f0762f9f6f07a3349fb3 (diff)
habanalabs: add h/w queues module
This patch adds the H/W queues module and the code to initialize Goya's various compute and DMA engines and their queues. Goya has 5 DMA channels, 8 TPC engines and a single MME engine. For each channel/engine, there is a H/W queue logic which is used to pass commands from the user to the H/W. That logic is called QMAN. There are two types of QMANs: external and internal. The DMA QMANs are considered external while the TPC and MME QMANs are considered internal. For each external queue there is a completion queue, which is located on the Host memory. The differences between external and internal QMANs are: 1. The location of the queue's memory. External QMANs are located on the Host memory while internal QMANs are located on the on-chip memory. 2. The external QMAN write an entry to a completion queue and sends an MSI-X interrupt upon completion of a command buffer that was given to it. The internal QMAN doesn't do that. Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/habanalabs/Makefile2
-rw-r--r--drivers/misc/habanalabs/device.c75
-rw-r--r--drivers/misc/habanalabs/goya/goya.c1311
-rw-r--r--drivers/misc/habanalabs/goya/goyaP.h7
-rw-r--r--drivers/misc/habanalabs/habanalabs.h174
-rw-r--r--drivers/misc/habanalabs/habanalabs_drv.c5
-rw-r--r--drivers/misc/habanalabs/hw_queue.c400
-rw-r--r--drivers/misc/habanalabs/include/armcp_if.h292
-rw-r--r--drivers/misc/habanalabs/include/goya/goya_async_events.h186
-rw-r--r--drivers/misc/habanalabs/include/goya/goya_packets.h129
-rw-r--r--drivers/misc/habanalabs/include/qman_if.h56
-rw-r--r--drivers/misc/habanalabs/irq.c149
-rw-r--r--include/uapi/misc/habanalabs.h29
13 files changed, 2807 insertions, 8 deletions
diff --git a/drivers/misc/habanalabs/Makefile b/drivers/misc/habanalabs/Makefile
index 2530c9b78ca4..c07f3ccb57dc 100644
--- a/drivers/misc/habanalabs/Makefile
+++ b/drivers/misc/habanalabs/Makefile
@@ -5,7 +5,7 @@
5obj-m := habanalabs.o 5obj-m := habanalabs.o
6 6
7habanalabs-y := habanalabs_drv.o device.o context.o asid.o habanalabs_ioctl.o \ 7habanalabs-y := habanalabs_drv.o device.o context.o asid.o habanalabs_ioctl.o \
8 command_buffer.o 8 command_buffer.o hw_queue.o irq.o
9 9
10include $(src)/goya/Makefile 10include $(src)/goya/Makefile
11habanalabs-y += $(HL_GOYA_FILES) 11habanalabs-y += $(HL_GOYA_FILES)
diff --git a/drivers/misc/habanalabs/device.c b/drivers/misc/habanalabs/device.c
index 5eefc2952be5..06e2b7f32499 100644
--- a/drivers/misc/habanalabs/device.c
+++ b/drivers/misc/habanalabs/device.c
@@ -174,13 +174,23 @@ static int device_early_init(struct hl_device *hdev)
174 if (rc) 174 if (rc)
175 goto early_fini; 175 goto early_fini;
176 176
177 hdev->cq_wq = alloc_workqueue("hl-free-jobs", WQ_UNBOUND, 0);
178 if (hdev->cq_wq == NULL) {
179 dev_err(hdev->dev, "Failed to allocate CQ workqueue\n");
180 rc = -ENOMEM;
181 goto asid_fini;
182 }
183
177 hl_cb_mgr_init(&hdev->kernel_cb_mgr); 184 hl_cb_mgr_init(&hdev->kernel_cb_mgr);
178 185
179 mutex_init(&hdev->fd_open_cnt_lock); 186 mutex_init(&hdev->fd_open_cnt_lock);
187 mutex_init(&hdev->send_cpu_message_lock);
180 atomic_set(&hdev->fd_open_cnt, 0); 188 atomic_set(&hdev->fd_open_cnt, 0);
181 189
182 return 0; 190 return 0;
183 191
192asid_fini:
193 hl_asid_fini(hdev);
184early_fini: 194early_fini:
185 if (hdev->asic_funcs->early_fini) 195 if (hdev->asic_funcs->early_fini)
186 hdev->asic_funcs->early_fini(hdev); 196 hdev->asic_funcs->early_fini(hdev);
@@ -196,9 +206,12 @@ early_fini:
196 */ 206 */
197static void device_early_fini(struct hl_device *hdev) 207static void device_early_fini(struct hl_device *hdev)
198{ 208{
209 mutex_destroy(&hdev->send_cpu_message_lock);
199 210
200 hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); 211 hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr);
201 212
213 destroy_workqueue(hdev->cq_wq);
214
202 hl_asid_fini(hdev); 215 hl_asid_fini(hdev);
203 216
204 if (hdev->asic_funcs->early_fini) 217 if (hdev->asic_funcs->early_fini)
@@ -277,7 +290,7 @@ int hl_device_resume(struct hl_device *hdev)
277 */ 290 */
278int hl_device_init(struct hl_device *hdev, struct class *hclass) 291int hl_device_init(struct hl_device *hdev, struct class *hclass)
279{ 292{
280 int rc; 293 int i, rc, cq_ready_cnt;
281 294
282 /* Create device */ 295 /* Create device */
283 rc = device_setup_cdev(hdev, hclass, hdev->id, &hl_ops); 296 rc = device_setup_cdev(hdev, hclass, hdev->id, &hl_ops);
@@ -298,11 +311,48 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
298 if (rc) 311 if (rc)
299 goto early_fini; 312 goto early_fini;
300 313
314 /*
315 * Initialize the H/W queues. Must be done before hw_init, because
316 * there the addresses of the kernel queue are being written to the
317 * registers of the device
318 */
319 rc = hl_hw_queues_create(hdev);
320 if (rc) {
321 dev_err(hdev->dev, "failed to initialize kernel queues\n");
322 goto sw_fini;
323 }
324
325 /*
326 * Initialize the completion queues. Must be done before hw_init,
327 * because there the addresses of the completion queues are being
328 * passed as arguments to request_irq
329 */
330 hdev->completion_queue =
331 kcalloc(hdev->asic_prop.completion_queues_count,
332 sizeof(*hdev->completion_queue), GFP_KERNEL);
333
334 if (!hdev->completion_queue) {
335 dev_err(hdev->dev, "failed to allocate completion queues\n");
336 rc = -ENOMEM;
337 goto hw_queues_destroy;
338 }
339
340 for (i = 0, cq_ready_cnt = 0;
341 i < hdev->asic_prop.completion_queues_count;
342 i++, cq_ready_cnt++) {
343 rc = hl_cq_init(hdev, &hdev->completion_queue[i], i);
344 if (rc) {
345 dev_err(hdev->dev,
346 "failed to initialize completion queue\n");
347 goto cq_fini;
348 }
349 }
350
301 /* Allocate the kernel context */ 351 /* Allocate the kernel context */
302 hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx), GFP_KERNEL); 352 hdev->kernel_ctx = kzalloc(sizeof(*hdev->kernel_ctx), GFP_KERNEL);
303 if (!hdev->kernel_ctx) { 353 if (!hdev->kernel_ctx) {
304 rc = -ENOMEM; 354 rc = -ENOMEM;
305 goto sw_fini; 355 goto cq_fini;
306 } 356 }
307 357
308 hdev->user_ctx = NULL; 358 hdev->user_ctx = NULL;
@@ -328,6 +378,14 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
328 378
329 hdev->disabled = false; 379 hdev->disabled = false;
330 380
381 /* Check that the communication with the device is working */
382 rc = hdev->asic_funcs->test_queues(hdev);
383 if (rc) {
384 dev_err(hdev->dev, "Failed to detect if device is alive\n");
385 rc = 0;
386 goto out_disabled;
387 }
388
331 dev_notice(hdev->dev, 389 dev_notice(hdev->dev,
332 "Successfully added device to habanalabs driver\n"); 390 "Successfully added device to habanalabs driver\n");
333 391
@@ -339,6 +397,12 @@ release_ctx:
339 "kernel ctx is still alive on initialization failure\n"); 397 "kernel ctx is still alive on initialization failure\n");
340free_ctx: 398free_ctx:
341 kfree(hdev->kernel_ctx); 399 kfree(hdev->kernel_ctx);
400cq_fini:
401 for (i = 0 ; i < cq_ready_cnt ; i++)
402 hl_cq_fini(hdev, &hdev->completion_queue[i]);
403 kfree(hdev->completion_queue);
404hw_queues_destroy:
405 hl_hw_queues_destroy(hdev);
342sw_fini: 406sw_fini:
343 hdev->asic_funcs->sw_fini(hdev); 407 hdev->asic_funcs->sw_fini(hdev);
344early_fini: 408early_fini:
@@ -368,6 +432,7 @@ out_disabled:
368 */ 432 */
369void hl_device_fini(struct hl_device *hdev) 433void hl_device_fini(struct hl_device *hdev)
370{ 434{
435 int i;
371 dev_info(hdev->dev, "Removing device\n"); 436 dev_info(hdev->dev, "Removing device\n");
372 437
373 /* Mark device as disabled */ 438 /* Mark device as disabled */
@@ -382,6 +447,12 @@ void hl_device_fini(struct hl_device *hdev)
382 /* Reset the H/W. It will be in idle state after this returns */ 447 /* Reset the H/W. It will be in idle state after this returns */
383 hdev->asic_funcs->hw_fini(hdev, true); 448 hdev->asic_funcs->hw_fini(hdev, true);
384 449
450 for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
451 hl_cq_fini(hdev, &hdev->completion_queue[i]);
452 kfree(hdev->completion_queue);
453
454 hl_hw_queues_destroy(hdev);
455