Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

gpu: host1x: Add context device management code

Add code to register context devices from device tree, allocate them
out and manage their refcounts.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Mikko Perttunen and committed by
Thierry Reding
8aa5bcb6 a72d4b18

+248 -1
+3
drivers/gpu/host1x/Makefile
··· 17 17 hw/host1x06.o \ 18 18 hw/host1x07.o 19 19 20 + host1x-$(CONFIG_IOMMU_API) += \ 21 + context.o 22 + 20 23 obj-$(CONFIG_TEGRA_HOST1X) += host1x.o 21 24 obj-$(CONFIG_TEGRA_HOST1X_CONTEXT_BUS) += context_bus.o
+160
drivers/gpu/host1x/context.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2021, NVIDIA Corporation. 4 + */ 5 + 6 + #include <linux/device.h> 7 + #include <linux/kref.h> 8 + #include <linux/of.h> 9 + #include <linux/of_platform.h> 10 + #include <linux/pid.h> 11 + #include <linux/slab.h> 12 + 13 + #include "context.h" 14 + #include "dev.h" 15 + 16 + int host1x_memory_context_list_init(struct host1x *host1x) 17 + { 18 + struct host1x_memory_context_list *cdl = &host1x->context_list; 19 + struct device_node *node = host1x->dev->of_node; 20 + struct host1x_memory_context *ctx; 21 + unsigned int i; 22 + int err; 23 + 24 + cdl->devs = NULL; 25 + cdl->len = 0; 26 + mutex_init(&cdl->lock); 27 + 28 + err = of_property_count_u32_elems(node, "iommu-map"); 29 + if (err < 0) 30 + return 0; 31 + 32 + cdl->devs = kcalloc(err, sizeof(*cdl->devs), GFP_KERNEL); 33 + if (!cdl->devs) 34 + return -ENOMEM; 35 + cdl->len = err / 4; 36 + 37 + for (i = 0; i < cdl->len; i++) { 38 + struct iommu_fwspec *fwspec; 39 + 40 + ctx = &cdl->devs[i]; 41 + 42 + ctx->host = host1x; 43 + 44 + device_initialize(&ctx->dev); 45 + 46 + /* 47 + * Due to an issue with T194 NVENC, only 38 bits can be used. 48 + * Anyway, 256GiB of IOVA ought to be enough for anyone. 49 + */ 50 + ctx->dma_mask = DMA_BIT_MASK(38); 51 + ctx->dev.dma_mask = &ctx->dma_mask; 52 + ctx->dev.coherent_dma_mask = ctx->dma_mask; 53 + dev_set_name(&ctx->dev, "host1x-ctx.%d", i); 54 + ctx->dev.bus = &host1x_context_device_bus_type; 55 + ctx->dev.parent = host1x->dev; 56 + 57 + dma_set_max_seg_size(&ctx->dev, UINT_MAX); 58 + 59 + err = device_add(&ctx->dev); 60 + if (err) { 61 + dev_err(host1x->dev, "could not add context device %d: %d\n", i, err); 62 + goto del_devices; 63 + } 64 + 65 + err = of_dma_configure_id(&ctx->dev, node, true, &i); 66 + if (err) { 67 + dev_err(host1x->dev, "IOMMU configuration failed for context device %d: %d\n", 68 + i, err); 69 + device_del(&ctx->dev); 70 + goto del_devices; 71 + } 72 + 73 + fwspec = dev_iommu_fwspec_get(&ctx->dev); 74 + if (!fwspec || !device_iommu_mapped(&ctx->dev)) { 75 + dev_err(host1x->dev, "Context device %d has no IOMMU!\n", i); 76 + device_del(&ctx->dev); 77 + goto del_devices; 78 + } 79 + 80 + ctx->stream_id = fwspec->ids[0] & 0xffff; 81 + } 82 + 83 + return 0; 84 + 85 + del_devices: 86 + while (i--) 87 + device_del(&cdl->devs[i].dev); 88 + 89 + kfree(cdl->devs); 90 + cdl->len = 0; 91 + 92 + return err; 93 + } 94 + 95 + void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl) 96 + { 97 + unsigned int i; 98 + 99 + for (i = 0; i < cdl->len; i++) 100 + device_del(&cdl->devs[i].dev); 101 + 102 + kfree(cdl->devs); 103 + cdl->len = 0; 104 + } 105 + 106 + struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x, 107 + struct pid *pid) 108 + { 109 + struct host1x_memory_context_list *cdl = &host1x->context_list; 110 + struct host1x_memory_context *free = NULL; 111 + int i; 112 + 113 + if (!cdl->len) 114 + return ERR_PTR(-EOPNOTSUPP); 115 + 116 + mutex_lock(&cdl->lock); 117 + 118 + for (i = 0; i < cdl->len; i++) { 119 + struct host1x_memory_context *cd = &cdl->devs[i]; 120 + 121 + if (cd->owner == pid) { 122 + refcount_inc(&cd->ref); 123 + mutex_unlock(&cdl->lock); 124 + return cd; 125 + } else if (!cd->owner && !free) { 126 + free = cd; 127 + } 128 + } 129 + 130 + if (!free) { 131 + mutex_unlock(&cdl->lock); 132 + return ERR_PTR(-EBUSY); 133 + } 134 + 135 + refcount_set(&free->ref, 1); 136 + free->owner = get_pid(pid); 137 + 138 + mutex_unlock(&cdl->lock); 139 + 140 + return free; 141 + } 142 + EXPORT_SYMBOL_GPL(host1x_memory_context_alloc); 143 + 144 + void host1x_memory_context_get(struct host1x_memory_context *cd) 145 + { 146 + refcount_inc(&cd->ref); 147 + } 148 + EXPORT_SYMBOL_GPL(host1x_memory_context_get); 149 + 150 + void host1x_memory_context_put(struct host1x_memory_context *cd) 151 + { 152 + struct host1x_memory_context_list *cdl = &cd->host->context_list; 153 + 154 + if (refcount_dec_and_mutex_lock(&cd->ref, &cdl->lock)) { 155 + put_pid(cd->owner); 156 + cd->owner = NULL; 157 + mutex_unlock(&cdl->lock); 158 + } 159 + } 160 + EXPORT_SYMBOL_GPL(host1x_memory_context_put);
+38
drivers/gpu/host1x/context.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Host1x context devices 4 + * 5 + * Copyright (c) 2020, NVIDIA Corporation. 6 + */ 7 + 8 + #ifndef __HOST1X_CONTEXT_H 9 + #define __HOST1X_CONTEXT_H 10 + 11 + #include <linux/mutex.h> 12 + #include <linux/refcount.h> 13 + 14 + struct host1x; 15 + 16 + extern struct bus_type host1x_context_device_bus_type; 17 + 18 + struct host1x_memory_context_list { 19 + struct mutex lock; 20 + struct host1x_memory_context *devs; 21 + unsigned int len; 22 + }; 23 + 24 + #ifdef CONFIG_IOMMU_API 25 + int host1x_memory_context_list_init(struct host1x *host1x); 26 + void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl); 27 + #else 28 + static inline int host1x_memory_context_list_init(struct host1x *host1x) 29 + { 30 + return 0; 31 + } 32 + 33 + static inline void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl) 34 + { 35 + } 36 + #endif 37 + 38 + #endif
+11 -1
drivers/gpu/host1x/dev.c
··· 28 28 29 29 #include "bus.h" 30 30 #include "channel.h" 31 + #include "context.h" 31 32 #include "debug.h" 32 33 #include "dev.h" 33 34 #include "intr.h" ··· 504 503 goto iommu_exit; 505 504 } 506 505 506 + err = host1x_memory_context_list_init(host); 507 + if (err) { 508 + dev_err(&pdev->dev, "failed to initialize context list\n"); 509 + goto free_channels; 510 + } 511 + 507 512 err = host1x_syncpt_init(host); 508 513 if (err) { 509 514 dev_err(&pdev->dev, "failed to initialize syncpts\n"); 510 - goto free_channels; 515 + goto free_contexts; 511 516 } 512 517 513 518 err = host1x_intr_init(host, syncpt_irq); ··· 557 550 host1x_intr_deinit(host); 558 551 deinit_syncpt: 559 552 host1x_syncpt_deinit(host); 553 + free_contexts: 554 + host1x_memory_context_list_free(&host->context_list); 560 555 free_channels: 561 556 host1x_channel_list_free(&host->channel_list); 562 557 iommu_exit: ··· 580 571 581 572 host1x_intr_deinit(host); 582 573 host1x_syncpt_deinit(host); 574 + host1x_memory_context_list_free(&host->context_list); 583 575 host1x_channel_list_free(&host->channel_list); 584 576 host1x_iommu_exit(host); 585 577 host1x_bo_cache_destroy(&host->cache);
+2
drivers/gpu/host1x/dev.h
··· 14 14 15 15 #include "cdma.h" 16 16 #include "channel.h" 17 + #include "context.h" 17 18 #include "intr.h" 18 19 #include "job.h" 19 20 #include "syncpt.h" ··· 142 141 struct mutex syncpt_mutex; 143 142 144 143 struct host1x_channel_list channel_list; 144 + struct host1x_memory_context_list context_list; 145 145 146 146 struct dentry *debugfs; 147 147
+34
include/linux/host1x.h
··· 446 446 int tegra_mipi_start_calibration(struct tegra_mipi_device *device); 447 447 int tegra_mipi_finish_calibration(struct tegra_mipi_device *device); 448 448 449 + /* host1x memory contexts */ 450 + 451 + struct host1x_memory_context { 452 + struct host1x *host; 453 + 454 + refcount_t ref; 455 + struct pid *owner; 456 + 457 + struct device dev; 458 + u64 dma_mask; 459 + u32 stream_id; 460 + }; 461 + 462 + #ifdef CONFIG_IOMMU_API 463 + struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x, 464 + struct pid *pid); 465 + void host1x_memory_context_get(struct host1x_memory_context *cd); 466 + void host1x_memory_context_put(struct host1x_memory_context *cd); 467 + #else 468 + static inline struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x, 469 + struct pid *pid) 470 + { 471 + return NULL; 472 + } 473 + 474 + static inline void host1x_memory_context_get(struct host1x_memory_context *cd) 475 + { 476 + } 477 + 478 + static inline void host1x_memory_context_put(struct host1x_memory_context *cd) 479 + { 480 + } 481 + #endif 482 + 449 483 #endif