| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ |
|---|
| 3 | 4 | * Author: Rob Clark <rob.clark@linaro.org> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 7 | | - * the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | | - * |
|---|
| 14 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 15 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 16 | 5 | */ |
|---|
| 17 | 6 | |
|---|
| 7 | +#include <linux/dma-mapping.h> |
|---|
| 18 | 8 | #include <linux/seq_file.h> |
|---|
| 19 | 9 | #include <linux/shmem_fs.h> |
|---|
| 20 | 10 | #include <linux/spinlock.h> |
|---|
| 21 | 11 | #include <linux/pfn_t.h> |
|---|
| 22 | 12 | |
|---|
| 13 | +#include <drm/drm_prime.h> |
|---|
| 23 | 14 | #include <drm/drm_vma_manager.h> |
|---|
| 24 | 15 | |
|---|
| 25 | 16 | #include "omap_drv.h" |
|---|
| .. | .. |
|---|
| 76 | 67 | /** |
|---|
| 77 | 68 | * # of users of dma_addr |
|---|
| 78 | 69 | */ |
|---|
| 79 | | - u32 dma_addr_cnt; |
|---|
| 70 | + refcount_t dma_addr_cnt; |
|---|
| 80 | 71 | |
|---|
| 81 | 72 | /** |
|---|
| 82 | 73 | * If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag |
|---|
| .. | .. |
|---|
| 205 | 196 | struct omap_gem_object *omap_obj = to_omap_bo(obj); |
|---|
| 206 | 197 | struct omap_drm_private *priv = obj->dev->dev_private; |
|---|
| 207 | 198 | |
|---|
| 208 | | - if (omap_obj->flags & OMAP_BO_TILED) { |
|---|
| 199 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) { |
|---|
| 209 | 200 | enum tiler_fmt fmt = gem2fmt(omap_obj->flags); |
|---|
| 210 | 201 | int i; |
|---|
| 211 | 202 | |
|---|
| .. | .. |
|---|
| 333 | 324 | struct omap_gem_object *omap_obj = to_omap_bo(obj); |
|---|
| 334 | 325 | size_t size = obj->size; |
|---|
| 335 | 326 | |
|---|
| 336 | | - if (omap_obj->flags & OMAP_BO_TILED) { |
|---|
| 327 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) { |
|---|
| 337 | 328 | /* for tiled buffers, the virtual size has stride rounded up |
|---|
| 338 | 329 | * to 4kb.. (to hide the fact that row n+1 might start 16kb or |
|---|
| 339 | 330 | * 32kb later!). But we don't back the entire buffer with |
|---|
| .. | .. |
|---|
| 522 | 513 | * probably trigger put_pages()? |
|---|
| 523 | 514 | */ |
|---|
| 524 | 515 | |
|---|
| 525 | | - if (omap_obj->flags & OMAP_BO_TILED) |
|---|
| 516 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) |
|---|
| 526 | 517 | ret = omap_gem_fault_2d(obj, vma, vmf); |
|---|
| 527 | 518 | else |
|---|
| 528 | 519 | ret = omap_gem_fault_1d(obj, vma, vmf); |
|---|
| .. | .. |
|---|
| 638 | 629 | |
|---|
| 639 | 630 | *offset = omap_gem_mmap_offset(obj); |
|---|
| 640 | 631 | |
|---|
| 641 | | - drm_gem_object_unreference_unlocked(obj); |
|---|
| 632 | + drm_gem_object_put(obj); |
|---|
| 642 | 633 | |
|---|
| 643 | 634 | fail: |
|---|
| 644 | 635 | return ret; |
|---|
| .. | .. |
|---|
| 782 | 773 | mutex_lock(&omap_obj->lock); |
|---|
| 783 | 774 | |
|---|
| 784 | 775 | if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { |
|---|
| 785 | | - if (omap_obj->dma_addr_cnt == 0) { |
|---|
| 776 | + if (refcount_read(&omap_obj->dma_addr_cnt) == 0) { |
|---|
| 786 | 777 | u32 npages = obj->size >> PAGE_SHIFT; |
|---|
| 787 | 778 | enum tiler_fmt fmt = gem2fmt(omap_obj->flags); |
|---|
| 788 | 779 | struct tiler_block *block; |
|---|
| 789 | 780 | |
|---|
| 790 | 781 | BUG_ON(omap_obj->block); |
|---|
| 791 | 782 | |
|---|
| 783 | + refcount_set(&omap_obj->dma_addr_cnt, 1); |
|---|
| 784 | + |
|---|
| 792 | 785 | ret = omap_gem_attach_pages(obj); |
|---|
| 793 | 786 | if (ret) |
|---|
| 794 | 787 | goto fail; |
|---|
| 795 | 788 | |
|---|
| 796 | | - if (omap_obj->flags & OMAP_BO_TILED) { |
|---|
| 789 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) { |
|---|
| 797 | 790 | block = tiler_reserve_2d(fmt, |
|---|
| 798 | 791 | omap_obj->width, |
|---|
| 799 | 792 | omap_obj->height, 0); |
|---|
| .. | .. |
|---|
| 822 | 815 | omap_obj->block = block; |
|---|
| 823 | 816 | |
|---|
| 824 | 817 | DBG("got dma address: %pad", &omap_obj->dma_addr); |
|---|
| 818 | + } else { |
|---|
| 819 | + refcount_inc(&omap_obj->dma_addr_cnt); |
|---|
| 825 | 820 | } |
|---|
| 826 | 821 | |
|---|
| 827 | | - omap_obj->dma_addr_cnt++; |
|---|
| 828 | | - |
|---|
| 829 | | - *dma_addr = omap_obj->dma_addr; |
|---|
| 822 | + if (dma_addr) |
|---|
| 823 | + *dma_addr = omap_obj->dma_addr; |
|---|
| 830 | 824 | } else if (omap_gem_is_contiguous(omap_obj)) { |
|---|
| 831 | | - *dma_addr = omap_obj->dma_addr; |
|---|
| 825 | + if (dma_addr) |
|---|
| 826 | + *dma_addr = omap_obj->dma_addr; |
|---|
| 832 | 827 | } else { |
|---|
| 833 | 828 | ret = -EINVAL; |
|---|
| 834 | 829 | goto fail; |
|---|
| .. | .. |
|---|
| 841 | 836 | } |
|---|
| 842 | 837 | |
|---|
| 843 | 838 | /** |
|---|
| 839 | + * omap_gem_unpin_locked() - Unpin a GEM object from memory |
|---|
| 840 | + * @obj: the GEM object |
|---|
| 841 | + * |
|---|
| 842 | + * omap_gem_unpin() without locking. |
|---|
| 843 | + */ |
|---|
| 844 | +static void omap_gem_unpin_locked(struct drm_gem_object *obj) |
|---|
| 845 | +{ |
|---|
| 846 | + struct omap_drm_private *priv = obj->dev->dev_private; |
|---|
| 847 | + struct omap_gem_object *omap_obj = to_omap_bo(obj); |
|---|
| 848 | + int ret; |
|---|
| 849 | + |
|---|
| 850 | + if (omap_gem_is_contiguous(omap_obj) || !priv->has_dmm) |
|---|
| 851 | + return; |
|---|
| 852 | + |
|---|
| 853 | + if (refcount_dec_and_test(&omap_obj->dma_addr_cnt)) { |
|---|
| 854 | + ret = tiler_unpin(omap_obj->block); |
|---|
| 855 | + if (ret) { |
|---|
| 856 | + dev_err(obj->dev->dev, |
|---|
| 857 | + "could not unpin pages: %d\n", ret); |
|---|
| 858 | + } |
|---|
| 859 | + ret = tiler_release(omap_obj->block); |
|---|
| 860 | + if (ret) { |
|---|
| 861 | + dev_err(obj->dev->dev, |
|---|
| 862 | + "could not release unmap: %d\n", ret); |
|---|
| 863 | + } |
|---|
| 864 | + omap_obj->dma_addr = 0; |
|---|
| 865 | + omap_obj->block = NULL; |
|---|
| 866 | + } |
|---|
| 867 | +} |
|---|
| 868 | + |
|---|
| 869 | +/** |
|---|
| 844 | 870 | * omap_gem_unpin() - Unpin a GEM object from memory |
|---|
| 845 | 871 | * @obj: the GEM object |
|---|
| 846 | 872 | * |
|---|
| 847 | 873 | * Unpin the given GEM object previously pinned with omap_gem_pin(). Pins are |
|---|
| 848 | | - * reference-counted, the actualy unpin will only be performed when the number |
|---|
| 874 | + * reference-counted, the actual unpin will only be performed when the number |
|---|
| 849 | 875 | * of calls to this function matches the number of calls to omap_gem_pin(). |
|---|
| 850 | 876 | */ |
|---|
| 851 | 877 | void omap_gem_unpin(struct drm_gem_object *obj) |
|---|
| 852 | 878 | { |
|---|
| 853 | 879 | struct omap_gem_object *omap_obj = to_omap_bo(obj); |
|---|
| 854 | | - int ret; |
|---|
| 855 | 880 | |
|---|
| 856 | 881 | mutex_lock(&omap_obj->lock); |
|---|
| 857 | | - |
|---|
| 858 | | - if (omap_obj->dma_addr_cnt > 0) { |
|---|
| 859 | | - omap_obj->dma_addr_cnt--; |
|---|
| 860 | | - if (omap_obj->dma_addr_cnt == 0) { |
|---|
| 861 | | - ret = tiler_unpin(omap_obj->block); |
|---|
| 862 | | - if (ret) { |
|---|
| 863 | | - dev_err(obj->dev->dev, |
|---|
| 864 | | - "could not unpin pages: %d\n", ret); |
|---|
| 865 | | - } |
|---|
| 866 | | - ret = tiler_release(omap_obj->block); |
|---|
| 867 | | - if (ret) { |
|---|
| 868 | | - dev_err(obj->dev->dev, |
|---|
| 869 | | - "could not release unmap: %d\n", ret); |
|---|
| 870 | | - } |
|---|
| 871 | | - omap_obj->dma_addr = 0; |
|---|
| 872 | | - omap_obj->block = NULL; |
|---|
| 873 | | - } |
|---|
| 874 | | - } |
|---|
| 875 | | - |
|---|
| 882 | + omap_gem_unpin_locked(obj); |
|---|
| 876 | 883 | mutex_unlock(&omap_obj->lock); |
|---|
| 877 | 884 | } |
|---|
| 878 | 885 | |
|---|
| .. | .. |
|---|
| 888 | 895 | |
|---|
| 889 | 896 | mutex_lock(&omap_obj->lock); |
|---|
| 890 | 897 | |
|---|
| 891 | | - if ((omap_obj->dma_addr_cnt > 0) && omap_obj->block && |
|---|
| 892 | | - (omap_obj->flags & OMAP_BO_TILED)) { |
|---|
| 898 | + if ((refcount_read(&omap_obj->dma_addr_cnt) > 0) && omap_obj->block && |
|---|
| 899 | + (omap_obj->flags & OMAP_BO_TILED_MASK)) { |
|---|
| 893 | 900 | *dma_addr = tiler_tsptr(omap_obj->block, orient, x, y); |
|---|
| 894 | 901 | ret = 0; |
|---|
| 895 | 902 | } |
|---|
| .. | .. |
|---|
| 904 | 911 | { |
|---|
| 905 | 912 | struct omap_gem_object *omap_obj = to_omap_bo(obj); |
|---|
| 906 | 913 | int ret = -EINVAL; |
|---|
| 907 | | - if (omap_obj->flags & OMAP_BO_TILED) |
|---|
| 914 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) |
|---|
| 908 | 915 | ret = tiler_stride(gem2fmt(omap_obj->flags), orient); |
|---|
| 909 | 916 | return ret; |
|---|
| 910 | 917 | } |
|---|
| .. | .. |
|---|
| 1039 | 1046 | |
|---|
| 1040 | 1047 | seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", |
|---|
| 1041 | 1048 | omap_obj->flags, obj->name, kref_read(&obj->refcount), |
|---|
| 1042 | | - off, &omap_obj->dma_addr, omap_obj->dma_addr_cnt, |
|---|
| 1049 | + off, &omap_obj->dma_addr, |
|---|
| 1050 | + refcount_read(&omap_obj->dma_addr_cnt), |
|---|
| 1043 | 1051 | omap_obj->vaddr, omap_obj->roll); |
|---|
| 1044 | 1052 | |
|---|
| 1045 | | - if (omap_obj->flags & OMAP_BO_TILED) { |
|---|
| 1053 | + if (omap_obj->flags & OMAP_BO_TILED_MASK) { |
|---|
| 1046 | 1054 | seq_printf(m, " %dx%d", omap_obj->width, omap_obj->height); |
|---|
| 1047 | 1055 | if (omap_obj->block) { |
|---|
| 1048 | 1056 | struct tcm_area *area = &omap_obj->block->area; |
|---|
| .. | .. |
|---|
| 1102 | 1110 | mutex_lock(&omap_obj->lock); |
|---|
| 1103 | 1111 | |
|---|
| 1104 | 1112 | /* The object should not be pinned. */ |
|---|
| 1105 | | - WARN_ON(omap_obj->dma_addr_cnt > 0); |
|---|
| 1113 | + WARN_ON(refcount_read(&omap_obj->dma_addr_cnt) > 0); |
|---|
| 1106 | 1114 | |
|---|
| 1107 | 1115 | if (omap_obj->pages) { |
|---|
| 1108 | 1116 | if (omap_obj->flags & OMAP_BO_MEM_DMABUF) |
|---|
| .. | .. |
|---|
| 1129 | 1137 | kfree(omap_obj); |
|---|
| 1130 | 1138 | } |
|---|
| 1131 | 1139 | |
|---|
| 1140 | +static bool omap_gem_validate_flags(struct drm_device *dev, u32 flags) |
|---|
| 1141 | +{ |
|---|
| 1142 | + struct omap_drm_private *priv = dev->dev_private; |
|---|
| 1143 | + |
|---|
| 1144 | + switch (flags & OMAP_BO_CACHE_MASK) { |
|---|
| 1145 | + case OMAP_BO_CACHED: |
|---|
| 1146 | + case OMAP_BO_WC: |
|---|
| 1147 | + case OMAP_BO_CACHE_MASK: |
|---|
| 1148 | + break; |
|---|
| 1149 | + |
|---|
| 1150 | + default: |
|---|
| 1151 | + return false; |
|---|
| 1152 | + } |
|---|
| 1153 | + |
|---|
| 1154 | + if (flags & OMAP_BO_TILED_MASK) { |
|---|
| 1155 | + if (!priv->usergart) |
|---|
| 1156 | + return false; |
|---|
| 1157 | + |
|---|
| 1158 | + switch (flags & OMAP_BO_TILED_MASK) { |
|---|
| 1159 | + case OMAP_BO_TILED_8: |
|---|
| 1160 | + case OMAP_BO_TILED_16: |
|---|
| 1161 | + case OMAP_BO_TILED_32: |
|---|
| 1162 | + break; |
|---|
| 1163 | + |
|---|
| 1164 | + default: |
|---|
| 1165 | + return false; |
|---|
| 1166 | + } |
|---|
| 1167 | + } |
|---|
| 1168 | + |
|---|
| 1169 | + return true; |
|---|
| 1170 | +} |
|---|
| 1171 | + |
|---|
| 1132 | 1172 | /* GEM buffer object constructor */ |
|---|
| 1133 | 1173 | struct drm_gem_object *omap_gem_new(struct drm_device *dev, |
|---|
| 1134 | 1174 | union omap_gem_size gsize, u32 flags) |
|---|
| .. | .. |
|---|
| 1140 | 1180 | size_t size; |
|---|
| 1141 | 1181 | int ret; |
|---|
| 1142 | 1182 | |
|---|
| 1143 | | - /* Validate the flags and compute the memory and cache flags. */ |
|---|
| 1144 | | - if (flags & OMAP_BO_TILED) { |
|---|
| 1145 | | - if (!priv->usergart) { |
|---|
| 1146 | | - dev_err(dev->dev, "Tiled buffers require DMM\n"); |
|---|
| 1147 | | - return NULL; |
|---|
| 1148 | | - } |
|---|
| 1183 | + if (!omap_gem_validate_flags(dev, flags)) |
|---|
| 1184 | + return NULL; |
|---|
| 1149 | 1185 | |
|---|
| 1186 | + /* Validate the flags and compute the memory and cache flags. */ |
|---|
| 1187 | + if (flags & OMAP_BO_TILED_MASK) { |
|---|
| 1150 | 1188 | /* |
|---|
| 1151 | 1189 | * Tiled buffers are always shmem paged backed. When they are |
|---|
| 1152 | 1190 | * scanned out, they are remapped into DMM/TILER. |
|---|
| 1153 | 1191 | */ |
|---|
| 1154 | | - flags &= ~OMAP_BO_SCANOUT; |
|---|
| 1155 | 1192 | flags |= OMAP_BO_MEM_SHMEM; |
|---|
| 1156 | 1193 | |
|---|
| 1157 | 1194 | /* |
|---|
| .. | .. |
|---|
| 1162 | 1199 | flags |= tiler_get_cpu_cache_flags(); |
|---|
| 1163 | 1200 | } else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) { |
|---|
| 1164 | 1201 | /* |
|---|
| 1165 | | - * OMAP_BO_SCANOUT hints that the buffer doesn't need to be |
|---|
| 1166 | | - * tiled. However, to lower the pressure on memory allocation, |
|---|
| 1167 | | - * use contiguous memory only if no TILER is available. |
|---|
| 1202 | + * If we don't have DMM, we must allocate scanout buffers |
|---|
| 1203 | + * from contiguous DMA memory. |
|---|
| 1168 | 1204 | */ |
|---|
| 1169 | 1205 | flags |= OMAP_BO_MEM_DMA_API; |
|---|
| 1170 | 1206 | } else if (!(flags & OMAP_BO_MEM_DMABUF)) { |
|---|
| .. | .. |
|---|
| 1183 | 1219 | omap_obj->flags = flags; |
|---|
| 1184 | 1220 | mutex_init(&omap_obj->lock); |
|---|
| 1185 | 1221 | |
|---|
| 1186 | | - if (flags & OMAP_BO_TILED) { |
|---|
| 1222 | + if (flags & OMAP_BO_TILED_MASK) { |
|---|
| 1187 | 1223 | /* |
|---|
| 1188 | 1224 | * For tiled buffers align dimensions to slot boundaries and |
|---|
| 1189 | 1225 | * calculate size based on aligned dimensions. |
|---|
| .. | .. |
|---|
| 1261 | 1297 | omap_obj->dma_addr = sg_dma_address(sgt->sgl); |
|---|
| 1262 | 1298 | } else { |
|---|
| 1263 | 1299 | /* Create pages list from sgt */ |
|---|
| 1264 | | - struct sg_page_iter iter; |
|---|
| 1265 | 1300 | struct page **pages; |
|---|
| 1266 | 1301 | unsigned int npages; |
|---|
| 1267 | | - unsigned int i = 0; |
|---|
| 1302 | + unsigned int ret; |
|---|
| 1268 | 1303 | |
|---|
| 1269 | 1304 | npages = DIV_ROUND_UP(size, PAGE_SIZE); |
|---|
| 1270 | 1305 | pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1275 | 1310 | } |
|---|
| 1276 | 1311 | |
|---|
| 1277 | 1312 | omap_obj->pages = pages; |
|---|
| 1278 | | - |
|---|
| 1279 | | - for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) { |
|---|
| 1280 | | - pages[i++] = sg_page_iter_page(&iter); |
|---|
| 1281 | | - if (i > npages) |
|---|
| 1282 | | - break; |
|---|
| 1283 | | - } |
|---|
| 1284 | | - |
|---|
| 1285 | | - if (WARN_ON(i != npages)) { |
|---|
| 1313 | + ret = drm_prime_sg_to_page_addr_arrays(sgt, pages, NULL, |
|---|
| 1314 | + npages); |
|---|
| 1315 | + if (ret) { |
|---|
| 1286 | 1316 | omap_gem_free_object(obj); |
|---|
| 1287 | 1317 | obj = ERR_PTR(-ENOMEM); |
|---|
| 1288 | 1318 | goto done; |
|---|
| .. | .. |
|---|
| 1312 | 1342 | } |
|---|
| 1313 | 1343 | |
|---|
| 1314 | 1344 | /* drop reference from allocate - handle holds it now */ |
|---|
| 1315 | | - drm_gem_object_unreference_unlocked(obj); |
|---|
| 1345 | + drm_gem_object_put(obj); |
|---|
| 1316 | 1346 | |
|---|
| 1317 | 1347 | return 0; |
|---|
| 1318 | 1348 | } |
|---|