1*e1341f91SRob Clark /* SPDX-License-Identifier: GPL-2.0-only */ 2*e1341f91SRob Clark /* Copyright (C) 2020 Google, Inc */ 3*e1341f91SRob Clark 4*e1341f91SRob Clark #include "drm/drm_drv.h" 5*e1341f91SRob Clark 6*e1341f91SRob Clark #include "msm_drv.h" 7*e1341f91SRob Clark #include "msm_syncobj.h" 8*e1341f91SRob Clark 9*e1341f91SRob Clark struct drm_syncobj ** 10*e1341f91SRob Clark msm_syncobj_parse_deps(struct drm_device *dev, 11*e1341f91SRob Clark struct drm_sched_job *job, 12*e1341f91SRob Clark struct drm_file *file, 13*e1341f91SRob Clark uint64_t in_syncobjs_addr, 14*e1341f91SRob Clark uint32_t nr_in_syncobjs, 15*e1341f91SRob Clark size_t syncobj_stride) 16*e1341f91SRob Clark { 17*e1341f91SRob Clark struct drm_syncobj **syncobjs = NULL; 18*e1341f91SRob Clark struct drm_msm_syncobj syncobj_desc = {0}; 19*e1341f91SRob Clark int ret = 0; 20*e1341f91SRob Clark uint32_t i, j; 21*e1341f91SRob Clark 22*e1341f91SRob Clark syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs), 23*e1341f91SRob Clark GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); 24*e1341f91SRob Clark if (!syncobjs) 25*e1341f91SRob Clark return ERR_PTR(-ENOMEM); 26*e1341f91SRob Clark 27*e1341f91SRob Clark for (i = 0; i < nr_in_syncobjs; ++i) { 28*e1341f91SRob Clark uint64_t address = in_syncobjs_addr + i * syncobj_stride; 29*e1341f91SRob Clark 30*e1341f91SRob Clark if (copy_from_user(&syncobj_desc, 31*e1341f91SRob Clark u64_to_user_ptr(address), 32*e1341f91SRob Clark min(syncobj_stride, sizeof(syncobj_desc)))) { 33*e1341f91SRob Clark ret = -EFAULT; 34*e1341f91SRob Clark break; 35*e1341f91SRob Clark } 36*e1341f91SRob Clark 37*e1341f91SRob Clark if (syncobj_desc.point && 38*e1341f91SRob Clark !drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) { 39*e1341f91SRob Clark ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported"); 40*e1341f91SRob Clark break; 41*e1341f91SRob Clark } 42*e1341f91SRob Clark 43*e1341f91SRob Clark if (syncobj_desc.flags & ~MSM_SYNCOBJ_FLAGS) { 44*e1341f91SRob Clark ret = UERR(EINVAL, dev, "invalid syncobj flags: %x", syncobj_desc.flags); 45*e1341f91SRob Clark break; 46*e1341f91SRob Clark } 47*e1341f91SRob Clark 48*e1341f91SRob Clark ret = drm_sched_job_add_syncobj_dependency(job, file, 49*e1341f91SRob Clark syncobj_desc.handle, 50*e1341f91SRob Clark syncobj_desc.point); 51*e1341f91SRob Clark if (ret) 52*e1341f91SRob Clark break; 53*e1341f91SRob Clark 54*e1341f91SRob Clark if (syncobj_desc.flags & MSM_SYNCOBJ_RESET) { 55*e1341f91SRob Clark syncobjs[i] = drm_syncobj_find(file, syncobj_desc.handle); 56*e1341f91SRob Clark if (!syncobjs[i]) { 57*e1341f91SRob Clark ret = UERR(EINVAL, dev, "invalid syncobj handle: %u", i); 58*e1341f91SRob Clark break; 59*e1341f91SRob Clark } 60*e1341f91SRob Clark } 61*e1341f91SRob Clark } 62*e1341f91SRob Clark 63*e1341f91SRob Clark if (ret) { 64*e1341f91SRob Clark for (j = 0; j <= i; ++j) { 65*e1341f91SRob Clark if (syncobjs[j]) 66*e1341f91SRob Clark drm_syncobj_put(syncobjs[j]); 67*e1341f91SRob Clark } 68*e1341f91SRob Clark kfree(syncobjs); 69*e1341f91SRob Clark return ERR_PTR(ret); 70*e1341f91SRob Clark } 71*e1341f91SRob Clark return syncobjs; 72*e1341f91SRob Clark } 73*e1341f91SRob Clark 74*e1341f91SRob Clark void 75*e1341f91SRob Clark msm_syncobj_reset(struct drm_syncobj **syncobjs, uint32_t nr_syncobjs) 76*e1341f91SRob Clark { 77*e1341f91SRob Clark uint32_t i; 78*e1341f91SRob Clark 79*e1341f91SRob Clark for (i = 0; syncobjs && i < nr_syncobjs; ++i) { 80*e1341f91SRob Clark if (syncobjs[i]) 81*e1341f91SRob Clark drm_syncobj_replace_fence(syncobjs[i], NULL); 82*e1341f91SRob Clark } 83*e1341f91SRob Clark } 84*e1341f91SRob Clark 85*e1341f91SRob Clark struct msm_syncobj_post_dep * 86*e1341f91SRob Clark msm_syncobj_parse_post_deps(struct drm_device *dev, 87*e1341f91SRob Clark struct drm_file *file, 88*e1341f91SRob Clark uint64_t syncobjs_addr, 89*e1341f91SRob Clark uint32_t nr_syncobjs, 90*e1341f91SRob Clark size_t syncobj_stride) 91*e1341f91SRob Clark { 92*e1341f91SRob Clark struct msm_syncobj_post_dep *post_deps; 93*e1341f91SRob Clark struct drm_msm_syncobj syncobj_desc = {0}; 94*e1341f91SRob Clark int ret = 0; 95*e1341f91SRob Clark uint32_t i, j; 96*e1341f91SRob Clark 97*e1341f91SRob Clark post_deps = kcalloc(nr_syncobjs, sizeof(*post_deps), 98*e1341f91SRob Clark GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); 99*e1341f91SRob Clark if (!post_deps) 100*e1341f91SRob Clark return ERR_PTR(-ENOMEM); 101*e1341f91SRob Clark 102*e1341f91SRob Clark for (i = 0; i < nr_syncobjs; ++i) { 103*e1341f91SRob Clark uint64_t address = syncobjs_addr + i * syncobj_stride; 104*e1341f91SRob Clark 105*e1341f91SRob Clark if (copy_from_user(&syncobj_desc, 106*e1341f91SRob Clark u64_to_user_ptr(address), 107*e1341f91SRob Clark min(syncobj_stride, sizeof(syncobj_desc)))) { 108*e1341f91SRob Clark ret = -EFAULT; 109*e1341f91SRob Clark break; 110*e1341f91SRob Clark } 111*e1341f91SRob Clark 112*e1341f91SRob Clark post_deps[i].point = syncobj_desc.point; 113*e1341f91SRob Clark 114*e1341f91SRob Clark if (syncobj_desc.flags) { 115*e1341f91SRob Clark ret = UERR(EINVAL, dev, "invalid syncobj flags"); 116*e1341f91SRob Clark break; 117*e1341f91SRob Clark } 118*e1341f91SRob Clark 119*e1341f91SRob Clark if (syncobj_desc.point) { 120*e1341f91SRob Clark if (!drm_core_check_feature(dev, 121*e1341f91SRob Clark DRIVER_SYNCOBJ_TIMELINE)) { 122*e1341f91SRob Clark ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported"); 123*e1341f91SRob Clark break; 124*e1341f91SRob Clark } 125*e1341f91SRob Clark 126*e1341f91SRob Clark post_deps[i].chain = dma_fence_chain_alloc(); 127*e1341f91SRob Clark if (!post_deps[i].chain) { 128*e1341f91SRob Clark ret = -ENOMEM; 129*e1341f91SRob Clark break; 130*e1341f91SRob Clark } 131*e1341f91SRob Clark } 132*e1341f91SRob Clark 133*e1341f91SRob Clark post_deps[i].syncobj = 134*e1341f91SRob Clark drm_syncobj_find(file, syncobj_desc.handle); 135*e1341f91SRob Clark if (!post_deps[i].syncobj) { 136*e1341f91SRob Clark ret = UERR(EINVAL, dev, "invalid syncobj handle"); 137*e1341f91SRob Clark break; 138*e1341f91SRob Clark } 139*e1341f91SRob Clark } 140*e1341f91SRob Clark 141*e1341f91SRob Clark if (ret) { 142*e1341f91SRob Clark for (j = 0; j <= i; ++j) { 143*e1341f91SRob Clark dma_fence_chain_free(post_deps[j].chain); 144*e1341f91SRob Clark if (post_deps[j].syncobj) 145*e1341f91SRob Clark drm_syncobj_put(post_deps[j].syncobj); 146*e1341f91SRob Clark } 147*e1341f91SRob Clark 148*e1341f91SRob Clark kfree(post_deps); 149*e1341f91SRob Clark return ERR_PTR(ret); 150*e1341f91SRob Clark } 151*e1341f91SRob Clark 152*e1341f91SRob Clark return post_deps; 153*e1341f91SRob Clark } 154*e1341f91SRob Clark 155*e1341f91SRob Clark void 156*e1341f91SRob Clark msm_syncobj_process_post_deps(struct msm_syncobj_post_dep *post_deps, 157*e1341f91SRob Clark uint32_t count, struct dma_fence *fence) 158*e1341f91SRob Clark { 159*e1341f91SRob Clark uint32_t i; 160*e1341f91SRob Clark 161*e1341f91SRob Clark for (i = 0; post_deps && i < count; ++i) { 162*e1341f91SRob Clark if (post_deps[i].chain) { 163*e1341f91SRob Clark drm_syncobj_add_point(post_deps[i].syncobj, 164*e1341f91SRob Clark post_deps[i].chain, 165*e1341f91SRob Clark fence, post_deps[i].point); 166*e1341f91SRob Clark post_deps[i].chain = NULL; 167*e1341f91SRob Clark } else { 168*e1341f91SRob Clark drm_syncobj_replace_fence(post_deps[i].syncobj, 169*e1341f91SRob Clark fence); 170*e1341f91SRob Clark } 171*e1341f91SRob Clark } 172*e1341f91SRob Clark } 173