History

Merge branch 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux into drm-next

Highlights: - Cooling device support from Russell, to allow GPU throttling on system thermal overload. - Explicit fencing support from Philipp, implemented in a similar way to drm/msm. * 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux: drm/etnaviv: submit support for out-fences drm/etnaviv: return GPU fence through the submit structure drm/etnaviv: submit support for in-fences drm/etnaviv: add etnaviv cooling device drm/etnaviv: switch to postclose drm/etnaviv: add lockdep assert to fence allocation

Dave Airlie committed 9 years ago

Commit aed93ee2 parents 0e96133 78ec1877 files · +162 −25Browse files

Unified · Split

7 files
  1. drivers/gpu/drm/etnaviv/Kconfig +1 −0
  2. drivers/gpu/drm/etnaviv/etnaviv_drv.c +3 −3
  3. drivers/gpu/drm/etnaviv/etnaviv_gem.h +3 −1
  4. drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +63 −2
  5. drivers/gpu/drm/etnaviv/etnaviv_gpu.c +81 −18
  6. drivers/gpu/drm/etnaviv/etnaviv_gpu.h +3 −1
  7. include/uapi/drm/etnaviv_drm.h +8 −0
drivers/gpu/drm/etnaviv/Kconfig+1−0
@@ -5,6 +5,7 @@ config DRM_ETNAVIV · 4 unmodified lines
55 depends on ARCH_MXC || ARCH_DOVE || (ARM && COMPILE_TEST)
66 depends on MMU
77 select SHMEM
8+ select SYNC_FILE
89 select TMPFS
910 select IOMMU_API
1011 select IOMMU_SUPPORT
drivers/gpu/drm/etnaviv/etnaviv_drv.c+3−3
@@ -111,7 +111,7 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file) · 110 unmodified lines
111111 return 0;
112112 }
113113
114−static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file)
114+static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
115115 {
116116 struct etnaviv_drm_private *priv = dev->dev_private;
117117 struct etnaviv_file_private *ctx = file->driver_priv;
@@ -488,7 +488,7 @@ static struct drm_driver etnaviv_drm_driver = { · 370 unmodified lines
488488 DRIVER_PRIME |
489489 DRIVER_RENDER,
490490 .open = etnaviv_open,
491− .preclose = etnaviv_preclose,
491+ .postclose = etnaviv_postclose,
492492 .gem_free_object_unlocked = etnaviv_gem_free_object,
493493 .gem_vm_ops = &vm_ops,
494494 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
@@ -512,7 +512,7 @@ static struct drm_driver etnaviv_drm_driver = { · 17 unmodified lines
512512 .desc = "etnaviv DRM",
513513 .date = "20151214",
514514 .major = 1,
515− .minor = 0,
515+ .minor = 1,
516516 };
517517
518518 /*
drivers/gpu/drm/etnaviv/etnaviv_gem.h+3−1
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/reservation.h>
2121 #include "etnaviv_drv.h"
2222
23+struct dma_fence;
2324 struct etnaviv_gem_ops;
2425 struct etnaviv_gem_object;
2526
@@ -104,9 +105,10 @@ struct etnaviv_gem_submit { · 78 unmodified lines
104105 struct drm_device *dev;
105106 struct etnaviv_gpu *gpu;
106107 struct ww_acquire_ctx ticket;
107− u32 fence;
108+ struct dma_fence *fence;
108109 unsigned int nr_bos;
109110 struct etnaviv_gem_submit_bo bos[0];
111+ u32 flags;
110112 };
111113
112114 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c+63−2
@@ -14,7 +14,9 @@ · 13 unmodified lines
1414 * this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17+#include <linux/dma-fence-array.h>
1718 #include <linux/reservation.h>
19+#include <linux/sync_file.h>
1820 #include "etnaviv_cmdbuf.h"
1921 #include "etnaviv_drv.h"
2022 #include "etnaviv_gpu.h"
@@ -169,8 +171,10 @@ static int submit_fence_sync(const struct etnaviv_gem_submit *submit) · 148 unmodified lines
169171 for (i = 0; i < submit->nr_bos; i++) {
170172 struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
171173 bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE;
174+ bool explicit = !(submit->flags & ETNA_SUBMIT_NO_IMPLICIT);
172175
173− ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write);
176+ ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write,
177+ explicit);
174178 if (ret)
175179 break;
176180 }
@@ -290,6 +294,7 @@ static void submit_cleanup(struct etnaviv_gem_submit *submit) · 113 unmodified lines
290294 }
291295
292296 ww_acquire_fini(&submit->ticket);
297+ dma_fence_put(submit->fence);
293298 kfree(submit);
294299 }
295300
@@ -303,6 +308,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 7 unmodified lines
303308 struct etnaviv_gem_submit *submit;
304309 struct etnaviv_cmdbuf *cmdbuf;
305310 struct etnaviv_gpu *gpu;
311+ struct dma_fence *in_fence = NULL;
312+ struct sync_file *sync_file = NULL;
313+ int out_fence_fd = -1;
306314 void *stream;
307315 int ret;
308316
@@ -326,6 +334,11 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 17 unmodified lines
326334 return -EINVAL;
327335 }
328336
337+ if (args->flags & ~ETNA_SUBMIT_FLAGS) {
338+ DRM_ERROR("invalid flags: 0x%x\n", args->flags);
339+ return -EINVAL;
340+ }
341+
329342 /*
330343 * Copy the command submission and bo array to kernel space in
331344 * one go, and do this outside of any locks.
@@ -365,12 +378,22 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 33 unmodified lines
365378 goto err_submit_cmds;
366379 }
367380
381+ if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) {
382+ out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
383+ if (out_fence_fd < 0) {
384+ ret = out_fence_fd;
385+ goto err_submit_cmds;
386+ }
387+ }
388+
368389 submit = submit_create(dev, gpu, args->nr_bos);
369390 if (!submit) {
370391 ret = -ENOMEM;
371392 goto err_submit_cmds;
372393 }
373394
395+ submit->flags = args->flags;
396+
374397 ret = submit_lookup_objects(submit, file, bos, args->nr_bos);
375398 if (ret)
376399 goto err_submit_objects;
@@ -385,6 +408,24 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 8 unmodified lines
385408 goto err_submit_objects;
386409 }
387410
411+ if (args->flags & ETNA_SUBMIT_FENCE_FD_IN) {
412+ in_fence = sync_file_get_fence(args->fence_fd);
413+ if (!in_fence) {
414+ ret = -EINVAL;
415+ goto err_submit_objects;
416+ }
417+
418+ /*
419+ * Wait if the fence is from a foreign context, or if the fence
420+ * array contains any fence from a foreign context.
421+ */
422+ if (!dma_fence_match_context(in_fence, gpu->fence_context)) {
423+ ret = dma_fence_wait(in_fence, true);
424+ if (ret)
425+ goto err_submit_objects;
426+ }
427+ }
428+
388429 ret = submit_fence_sync(submit);
389430 if (ret)
390431 goto err_submit_objects;
@@ -405,7 +446,23 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, · 14 unmodified lines
405446 if (ret == 0)
406447 cmdbuf = NULL;
407448
408− args->fence = submit->fence;
449+ if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) {
450+ /*
451+ * This can be improved: ideally we want to allocate the sync
452+ * file before kicking off the GPU job and just attach the
453+ * fence to the sync file here, eliminating the ENOMEM
454+ * possibility at this stage.
455+ */
456+ sync_file = sync_file_create(submit->fence);
457+ if (!sync_file) {
458+ ret = -ENOMEM;
459+ goto out;
460+ }
461+ fd_install(out_fence_fd, sync_file->file);
462+ }
463+
464+ args->fence_fd = out_fence_fd;
465+ args->fence = submit->fence->seqno;
409466
410467 out:
411468 submit_unpin_objects(submit);
@@ -419,9 +476,13 @@ out: · 7 unmodified lines
419476 flush_workqueue(priv->wq);
420477
421478 err_submit_objects:
479+ if (in_fence)
480+ dma_fence_put(in_fence);
422481 submit_cleanup(submit);
423482
424483 err_submit_cmds:
484+ if (ret && (out_fence_fd >= 0))
485+ put_unused_fd(out_fence_fd);
425486 /* if we still own the cmdbuf */
426487 if (cmdbuf)
427488 etnaviv_cmdbuf_free(cmdbuf);
drivers/gpu/drm/etnaviv/etnaviv_gpu.c+81−18
@@ -18,6 +18,7 @@ · 17 unmodified lines
1818 #include <linux/dma-fence.h>
1919 #include <linux/moduleparam.h>
2020 #include <linux/of_device.h>
21+#include <linux/thermal.h>
2122
2223 #include "etnaviv_cmdbuf.h"
2324 #include "etnaviv_dump.h"
@@ -409,6 +410,17 @@ static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock) · 385 unmodified lines
409410 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
410411 }
411412
413+static void etnaviv_gpu_update_clock(struct etnaviv_gpu *gpu)
414+{
415+ unsigned int fscale = 1 << (6 - gpu->freq_scale);
416+ u32 clock;
417+
418+ clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
419+ VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale);
420+
421+ etnaviv_gpu_load_clock(gpu, clock);
422+}
423+
412424 static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
413425 {
414426 u32 control, idle;
@@ -426,11 +438,10 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) · 11 unmodified lines
426438 timeout = jiffies + msecs_to_jiffies(1000);
427439
428440 while (time_is_after_jiffies(timeout)) {
429− control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
430− VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
431−
432441 /* enable clock */
433− etnaviv_gpu_load_clock(gpu, control);
442+ etnaviv_gpu_update_clock(gpu);
443+
444+ control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
434445
435446 /* Wait for stable clock. Vivante's code waited for 1ms */
436447 usleep_range(1000, 10000);
@@ -490,11 +501,7 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) · 53 unmodified lines
490501 }
491502
492503 /* We rely on the GPU running, so program the clock */
493− control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
494− VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
495−
496− /* enable clock */
497− etnaviv_gpu_load_clock(gpu, control);
504+ etnaviv_gpu_update_clock(gpu);
498505
499506 return 0;
500507 }
@@ -1051,6 +1058,12 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) · 550 unmodified lines
10511058 {
10521059 struct etnaviv_fence *f;
10531060
1061+ /*
1062+ * GPU lock must already be held, otherwise fence completion order might
1063+ * not match the seqno order assigned here.
1064+ */
1065+ lockdep_assert_held(&gpu->lock);
1066+
10541067 f = kzalloc(sizeof(*f), GFP_KERNEL);
10551068 if (!f)
10561069 return NULL;
@@ -1064,7 +1077,7 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) · 7 unmodified lines
10641077 }
10651078
10661079 int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
1067− unsigned int context, bool exclusive)
1080+ unsigned int context, bool exclusive, bool explicit)
10681081 {
10691082 struct reservation_object *robj = etnaviv_obj->resv;
10701083 struct reservation_object_list *fobj;
@@ -1077,6 +1090,9 @@ int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj, · 6 unmodified lines
10771090 return ret;
10781091 }
10791092
1093+ if (explicit)
1094+ return 0;
1095+
10801096 /*
10811097 * If we have any shared fences, then the exclusive fence
10821098 * should be ignored as it will already have been signalled.
@@ -1321,8 +1337,8 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, · 238 unmodified lines
13211337 mutex_lock(&gpu->lock);
13221338
13231339 gpu->event[event].fence = fence;
1324− submit->fence = fence->seqno;
1325− gpu->active_fence = submit->fence;
1340+ submit->fence = dma_fence_get(fence);
1341+ gpu->active_fence = submit->fence->seqno;
13261342
13271343 if (gpu->lastctx != cmdbuf->ctx) {
13281344 gpu->mmu->need_flush = true;
@@ -1526,17 +1542,13 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu) · 197 unmodified lines
15261542 #ifdef CONFIG_PM
15271543 static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
15281544 {
1529− u32 clock;
15301545 int ret;
15311546
15321547 ret = mutex_lock_killable(&gpu->lock);
15331548 if (ret)
15341549 return ret;
15351550
1536− clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS |
1537− VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40);
1538−
1539− etnaviv_gpu_load_clock(gpu, clock);
1551+ etnaviv_gpu_update_clock(gpu);
15401552 etnaviv_gpu_hw_init(gpu);
15411553
15421554 gpu->switch_context = true;
@@ -1548,6 +1560,47 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu) · 5 unmodified lines
15481560 }
15491561 #endif
15501562
1563+static int
1564+etnaviv_gpu_cooling_get_max_state(struct thermal_cooling_device *cdev,
1565+ unsigned long *state)
1566+{
1567+ *state = 6;
1568+
1569+ return 0;
1570+}
1571+
1572+static int
1573+etnaviv_gpu_cooling_get_cur_state(struct thermal_cooling_device *cdev,
1574+ unsigned long *state)
1575+{
1576+ struct etnaviv_gpu *gpu = cdev->devdata;
1577+
1578+ *state = gpu->freq_scale;
1579+
1580+ return 0;
1581+}
1582+
1583+static int
1584+etnaviv_gpu_cooling_set_cur_state(struct thermal_cooling_device *cdev,
1585+ unsigned long state)
1586+{
1587+ struct etnaviv_gpu *gpu = cdev->devdata;
1588+
1589+ mutex_lock(&gpu->lock);
1590+ gpu->freq_scale = state;
1591+ if (!pm_runtime_suspended(gpu->dev))
1592+ etnaviv_gpu_update_clock(gpu);
1593+ mutex_unlock(&gpu->lock);
1594+
1595+ return 0;
1596+}
1597+
1598+static struct thermal_cooling_device_ops cooling_ops = {
1599+ .get_max_state = etnaviv_gpu_cooling_get_max_state,
1600+ .get_cur_state = etnaviv_gpu_cooling_get_cur_state,
1601+ .set_cur_state = etnaviv_gpu_cooling_set_cur_state,
1602+};
1603+
15511604 static int etnaviv_gpu_bind(struct device *dev, struct device *master,
15521605 void *data)
15531606 {
@@ -1556,13 +1609,20 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, · 2 unmodified lines
15561609 struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
15571610 int ret;
15581611
1612+ gpu->cooling = thermal_of_cooling_device_register(dev->of_node,
1613+ (char *)dev_name(dev), gpu, &cooling_ops);
1614+ if (IS_ERR(gpu->cooling))
1615+ return PTR_ERR(gpu->cooling);
1616+
15591617 #ifdef CONFIG_PM
15601618 ret = pm_runtime_get_sync(gpu->dev);
15611619 #else
15621620 ret = etnaviv_gpu_clk_enable(gpu);
15631621 #endif
1564− if (ret < 0)
1622+ if (ret < 0) {
1623+ thermal_cooling_device_unregister(gpu->cooling);
15651624 return ret;
1625+ }
15661626
15671627 gpu->drm = drm;
15681628 gpu->fence_context = dma_fence_context_alloc(1);
@@ -1616,6 +1676,9 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, · 47 unmodified lines
16161676 }
16171677
16181678 gpu->drm = NULL;
1679+
1680+ thermal_cooling_device_unregister(gpu->cooling);
1681+ gpu->cooling = NULL;
16191682 }
16201683
16211684 static const struct component_ops gpu_ops = {
drivers/gpu/drm/etnaviv/etnaviv_gpu.h+3−1
@@ -97,6 +97,7 @@ struct etnaviv_cmdbuf; · 96 unmodified lines
9797
9898 struct etnaviv_gpu {
9999 struct drm_device *drm;
100+ struct thermal_cooling_device *cooling;
100101 struct device *dev;
101102 struct mutex lock;
102103 struct etnaviv_chip_identity identity;
@@ -150,6 +151,7 @@ struct etnaviv_gpu { · 47 unmodified lines
150151 u32 hangcheck_fence;
151152 u32 hangcheck_dma_addr;
152153 struct work_struct recover_work;
154+ unsigned int freq_scale;
153155 };
154156
155157 static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
@@ -181,7 +183,7 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); · 25 unmodified lines
181183 #endif
182184
183185 int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
184− unsigned int context, bool exclusive);
186+ unsigned int context, bool exclusive, bool implicit);
185187
186188 void etnaviv_gpu_retire(struct etnaviv_gpu *gpu);
187189 int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
include/uapi/drm/etnaviv_drm.h+8−0
@@ -154,6 +154,12 @@ struct drm_etnaviv_gem_submit_bo { · 153 unmodified lines
154154 * one or more cmdstream buffers. This allows for conditional execution
155155 * (context-restore), and IB buffers needed for per tile/bin draw cmds.
156156 */
157+#define ETNA_SUBMIT_NO_IMPLICIT 0x0001
158+#define ETNA_SUBMIT_FENCE_FD_IN 0x0002
159+#define ETNA_SUBMIT_FENCE_FD_OUT 0x0004
160+#define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \
161+ ETNA_SUBMIT_FENCE_FD_IN | \
162+ ETNA_SUBMIT_FENCE_FD_OUT)
157163 #define ETNA_PIPE_3D 0x00
158164 #define ETNA_PIPE_2D 0x01
159165 #define ETNA_PIPE_VG 0x02
@@ -167,6 +173,8 @@ struct drm_etnaviv_gem_submit { · 7 unmodified lines
167173 __u64 bos; /* in, ptr to array of submit_bo's */
168174 __u64 relocs; /* in, ptr to array of submit_reloc's */
169175 __u64 stream; /* in, ptr to cmdstream */
176+ __u32 flags; /* in, mask of ETNA_SUBMIT_x */
177+ __s32 fence_fd; /* in/out, fence fd (see ETNA_SUBMIT_FENCE_FD_x) */
170178 };
171179
172180 /* The normal way to synchronize with the GPU is just to CPU_PREP on

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t