Loading drivers/gpu/msm/adreno.h +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #define KGSL_CMD_FLAGS_WFI BIT(2) #define KGSL_CMD_FLAGS_PROFILE BIT(3) #define KGSL_CMD_FLAGS_PWRON_FIXUP BIT(4) #define KGSL_CMD_FLAGS_MEMLIST BIT(5) /* Command identifiers */ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF Loading drivers/gpu/msm/adreno_dispatch.c +4 −4 Original line number Diff line number Diff line Loading @@ -825,11 +825,11 @@ static void mark_guilty_context(struct kgsl_device *device, unsigned int id) static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base) { int i; struct kgsl_memobj_node *ib; for (i = 0; i < cmdbatch->ibcount; i++) { if (cmdbatch->ibdesc[i].gpuaddr == base) { cmdbatch->ibdesc[i].sizedwords = 0; list_for_each_entry(ib, &cmdbatch->cmdlist, node) { if (ib->gpuaddr == base) { ib->priv |= MEMOBJ_SKIP; if (base) return; } Loading drivers/gpu/msm/adreno_ringbuffer.c +49 −46 Original line number Diff line number Diff line Loading @@ -1078,20 +1078,20 @@ done: * core does */ static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv, struct kgsl_ibdesc *ibdesc) struct kgsl_memobj_node *ib) { struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* Check that the size of the IBs is under the allowable limit */ if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) { if (ib->sizedwords == 0 || ib->sizedwords > 0xFFFFF) { KGSL_DRV_ERR(device, "Invalid IB size 0x%zX\n", ibdesc->sizedwords); ib->sizedwords); return false; } if (unlikely(adreno_dev->ib_check_level >= 1) && !_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) { !_parse_ibs(dev_priv, ib->gpuaddr, ib->sizedwords)) { KGSL_DRV_ERR(device, "Could not verify the IBs\n"); return false; } Loading @@ -1108,17 +1108,16 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int i, ret; struct kgsl_memobj_node *ib; int ret; if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) return -EDEADLK; /* Verify the IBs before they get queued */ for (i = 0; i < cmdbatch->ibcount; i++) { if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i])) list_for_each_entry(ib, &cmdbatch->cmdlist, node) if (!_ringbuffer_verify_ib(dev_priv, ib)) return -EINVAL; } /* wait for the suspend gate */ wait_for_completion(&device->cmdbatch_gate); Loading Loading @@ -1210,22 +1209,22 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, struct kgsl_cmdbatch *cmdbatch) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_ibdesc *ibdesc; unsigned int numibs; struct kgsl_memobj_node *ib; unsigned int numibs = 0; unsigned int *link; unsigned int *cmds; unsigned int i; struct kgsl_context *context; struct adreno_context *drawctxt; unsigned int start_index = 0; bool use_preamble = true; int flags = KGSL_CMD_FLAGS_NONE; int ret; context = cmdbatch->context; drawctxt = ADRENO_CONTEXT(context); ibdesc = cmdbatch->ibdesc; numibs = cmdbatch->ibcount; /* Get the total IBs in the list */ list_for_each_entry(ib, &cmdbatch->cmdlist, node) numibs++; /* process any profiling results that are available into the log_buf */ adreno_profile_process_results(device); Loading Loading @@ -1260,7 +1259,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) && !test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) && (adreno_dev->drawctxt_active == drawctxt)) start_index = 1; use_preamble = false; /* * In skip mode don't issue the draw IBs but keep all the other Loading @@ -1268,43 +1267,47 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, * the accounting sane. Set start_index and numibs to 0 to just * generate the start and end markers and skip everything else */ if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) { start_index = 0; use_preamble = false; numibs = 0; } cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4), /* * Worst case size: * 2 - start of IB identifier * 1 - skip preamble * 3 * numibs - 3 per IB * 2 - end of IB identifier */ cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 5), GFP_KERNEL); if (!link) { ret = -ENOMEM; goto done; } if (!start_index) { *cmds++ = cp_nop_packet(1); *cmds++ = KGSL_START_OF_IB_IDENTIFIER; } else { *cmds++ = cp_nop_packet(4); *cmds++ = KGSL_START_OF_IB_IDENTIFIER; *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[0].gpuaddr; *cmds++ = ibdesc[0].sizedwords; } for (i = start_index; i < numibs; i++) { if (numibs) { list_for_each_entry(ib, &cmdbatch->cmdlist, node) { /* use the preamble? */ if ((ib->priv & MEMOBJ_PREAMBLE) && (use_preamble == false)) *cmds++ = cp_nop_packet(3); /* * Skip 0 sized IBs - these are presumed to have been removed * from consideration by the FT policy * Skip 0 sized IBs - these are presumed to have been * removed from consideration by the FT policy */ if (ibdesc[i].sizedwords == 0) if (ib->priv & MEMOBJ_SKIP) *cmds++ = cp_nop_packet(2); else *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[i].gpuaddr; *cmds++ = ibdesc[i].sizedwords; *cmds++ = ib->gpuaddr; *cmds++ = ib->sizedwords; } } *cmds++ = cp_nop_packet(1); Loading Loading @@ -1342,7 +1345,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, adreno_ringbuffer_set_constraint(device, cmdbatch); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); kgsl_cffdump_capture_ib_desc(device, context, cmdbatch); ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, drawctxt, Loading @@ -1355,8 +1358,8 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, 0x00000000, 0x80000000); done: trace_kgsl_issueibcmds(device, context->id, cmdbatch, cmdbatch->timestamp, cmdbatch->flags, ret, drawctxt->type); numibs, cmdbatch->timestamp, cmdbatch->flags, ret, drawctxt->type); kfree(link); return ret; Loading drivers/gpu/msm/kgsl.c +129 −46 Original line number Diff line number Diff line Loading @@ -63,6 +63,12 @@ #define KGSL_DMA_BIT_MASK DMA_BIT_MASK(32) #endif /* * Define an kmem cache for the memobj structures since we allocate and free * them so frequently */ static struct kmem_cache *memobjs_cache; static char *ksgl_mmu_type; module_param_named(mmutype, ksgl_mmu_type, charp, 0); MODULE_PARM_DESC(ksgl_mmu_type, Loading Loading @@ -1461,7 +1467,6 @@ void kgsl_cmdbatch_destroy_object(struct kref *kref) struct kgsl_cmdbatch, refcount); kgsl_context_put(cmdbatch->context); kfree(cmdbatch->ibdesc); kfree(cmdbatch); } Loading Loading @@ -1533,6 +1538,17 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, kgsl_cmdbatch_sync_event_put(event); } static inline void _free_memobj_list(struct list_head *list) { struct kgsl_memobj_node *mem, *tmpmem; /* Free the cmd mem here */ list_for_each_entry_safe(mem, tmpmem, list, node) { list_del_init(&mem->node); kmem_cache_free(memobjs_cache, mem); } } /** * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure * @cmdbatch: Pointer to the command batch object to destroy Loading @@ -1543,7 +1559,7 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, */ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) { struct kgsl_cmdbatch_sync_event *event, *tmp; struct kgsl_cmdbatch_sync_event *event, *tmpsync; LIST_HEAD(cancel_synclist); int sched = 0; Loading @@ -1563,7 +1579,7 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) * not to signal the callback. This guarantee ensures that * the reference count for the event and cmdbatch is correct. */ list_for_each_entry_safe(event, tmp, &cancel_synclist, node) { list_for_each_entry_safe(event, tmpsync, &cancel_synclist, node) { sched = 1; if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) { Loading @@ -1585,6 +1601,12 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) kgsl_cmdbatch_sync_event_put(event); } /* Destroy the cmdlist we created */ _free_memobj_list(&cmdbatch->cmdlist); /* Destroy the memlist we created */ _free_memobj_list(&cmdbatch->memlist); /* * If we cancelled an event, there's a good chance that the context is * on a dispatcher queue, so schedule to get it removed. Loading Loading @@ -1830,18 +1852,58 @@ int kgsl_cmdbatch_add_sync(struct kgsl_device *device, return ret; } /** * kgsl_cmdbatch_add_memobj() - Add an entry to a command batch * @cmdbatch: Pointer to the cmdbatch * @ibdesc: Pointer to the user-specified struct defining the memory or IB * @preamble: Flag to mark this ibdesc as a preamble (if known) * * Create a new memory entry in the cmdbatch based on the user specified * parameters */ int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc) { struct kgsl_memobj_node *mem; mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL); if (mem == NULL) return -ENOMEM; mem->gpuaddr = ibdesc->gpuaddr; mem->sizedwords = ibdesc->sizedwords; mem->priv = 0; /* sanitize the ibdesc ctrl flags */ ibdesc->ctrl &= KGSL_IBDESC_MEMLIST; if (cmdbatch->flags & KGSL_CMDBATCH_MEMLIST && ibdesc->ctrl & KGSL_IBDESC_MEMLIST) { /* add to the memlist */ list_add_tail(&mem->node, &cmdbatch->memlist); } else { /* set the preamble flag if directed to */ if (cmdbatch->context->flags & KGSL_CONTEXT_PREAMBLE && list_empty(&cmdbatch->cmdlist)) mem->priv = MEMOBJ_PREAMBLE; /* add to the cmd list */ list_add_tail(&mem->node, &cmdbatch->cmdlist); } return 0; } /** * kgsl_cmdbatch_create() - Create a new cmdbatch structure * @device: Pointer to a KGSL device struct * @context: Pointer to a KGSL context struct * @numibs: Number of indirect buffers to make room for in the cmdbatch * @flags: Flags for the cmdbatch * * Allocate an new cmdbatch structure and add enough room to store the list of * indirect buffers * Allocate an new cmdbatch structure */ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, struct kgsl_context *context, unsigned int flags, unsigned int numibs) struct kgsl_context *context, unsigned int flags) { struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL); if (cmdbatch == NULL) Loading @@ -1857,22 +1919,13 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, return ERR_PTR(-EINVAL); } if (!(flags & KGSL_CONTEXT_SYNC)) { cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs, GFP_KERNEL); if (cmdbatch->ibdesc == NULL) { kgsl_context_put(context); kfree(cmdbatch); return ERR_PTR(-ENOMEM); } } kref_init(&cmdbatch->refcount); INIT_LIST_HEAD(&cmdbatch->cmdlist); INIT_LIST_HEAD(&cmdbatch->synclist); INIT_LIST_HEAD(&cmdbatch->memlist); spin_lock_init(&cmdbatch->lock); cmdbatch->device = device; cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs; cmdbatch->context = context; cmdbatch->flags = flags & ~KGSL_CMDBATCH_SUBMIT_IB_LIST; Loading @@ -1895,27 +1948,27 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv, struct kgsl_cmdbatch *cmdbatch) { int i; struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_memobj_node *ib; for (i = 0; i < cmdbatch->ibcount; i++) { if (cmdbatch->ibdesc[i].sizedwords == 0) { list_for_each_entry(ib, &cmdbatch->cmdlist, node) { if (ib->sizedwords == 0) { KGSL_DRV_ERR(dev_priv->device, "invalid size ctx %d ib(%d) %lX/%zX\n", cmdbatch->context->id, i, cmdbatch->ibdesc[i].gpuaddr, cmdbatch->ibdesc[i].sizedwords); "invalid size ctx %d %lX/%zX\n", cmdbatch->context->id, ib->gpuaddr, ib->sizedwords); return false; } if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, cmdbatch->ibdesc[i].gpuaddr)) { ib->gpuaddr)) { KGSL_DRV_ERR(dev_priv->device, "Invalid address ctx %d ib(%d) %lX/%zX\n", cmdbatch->context->id, i, cmdbatch->ibdesc[i].gpuaddr, cmdbatch->ibdesc[i].sizedwords); "Invalid address ctx %d %lX/%zX\n", cmdbatch->context->id, ib->gpuaddr, ib->sizedwords); return false; } Loading @@ -1937,16 +1990,24 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy( struct kgsl_context *context, struct kgsl_ringbuffer_issueibcmds *param) { struct kgsl_memobj_node *mem; struct kgsl_cmdbatch *cmdbatch = kgsl_cmdbatch_create(device, context, param->flags, 1); kgsl_cmdbatch_create(device, context, param->flags); if (IS_ERR(cmdbatch)) return cmdbatch; cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr; cmdbatch->ibdesc[0].sizedwords = param->numibs; cmdbatch->ibcount = 1; cmdbatch->flags = param->flags; mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL); if (mem == NULL) { kgsl_cmdbatch_destroy(cmdbatch); return NULL; } mem->gpuaddr = param->ibdesc_addr; mem->sizedwords = param->numibs; mem->priv = 0; list_add_tail(&mem->node, &cmdbatch->cmdlist); return cmdbatch; } Loading @@ -1969,8 +2030,8 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device, void __user *synclist, unsigned int numsyncs) { struct kgsl_cmdbatch *cmdbatch = kgsl_cmdbatch_create(device, context, flags, numcmds); int ret = 0; kgsl_cmdbatch_create(device, context, flags); int ret = 0, i; if (IS_ERR(cmdbatch)) return cmdbatch; Loading @@ -1982,30 +2043,40 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device, } if (!(flags & KGSL_CMDBATCH_SYNC)) { if (copy_from_user(cmdbatch->ibdesc, cmdlist, sizeof(struct kgsl_ibdesc) * numcmds)) { struct kgsl_ibdesc ibdesc; void __user *uptr = cmdlist; for (i = 0; i < numcmds; i++) { memset(&ibdesc, 0, sizeof(ibdesc)); if (copy_from_user(&ibdesc, uptr, sizeof(ibdesc))) { ret = -EFAULT; goto done; } ret = kgsl_cmdbatch_add_memobj(cmdbatch, &ibdesc); if (ret) goto done; uptr += sizeof(ibdesc); } } if (synclist && numsyncs) { struct kgsl_cmd_syncpoint sync; void __user *uptr = synclist; int i; for (i = 0; i < numsyncs; i++) { memset(&sync, 0, sizeof(sync)); if (copy_from_user(&sync, uptr, sizeof(sync))) { ret = -EFAULT; break; goto done; } ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync); if (ret) break; goto done; uptr += sizeof(sync); } Loading Loading @@ -4282,6 +4353,10 @@ static void kgsl_core_exit(void) kgsl_driver.class = NULL; } /* free the memobject cache */ if (memobjs_cache) kmem_cache_destroy(memobjs_cache); kgsl_memfree_hist_exit(); unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); } Loading Loading @@ -4352,6 +4427,14 @@ static int __init kgsl_core_init(void) kgsl_events_init(); /* create the memobjs kmem cache */ memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0); if (memobjs_cache == NULL) { KGSL_CORE_ERR("failed to create memobjs_cache"); result = -ENOMEM; goto err; } if (kgsl_memfree_hist_init()) KGSL_CORE_ERR("failed to init memfree_hist"); Loading drivers/gpu/msm/kgsl.h +3 −0 Original line number Diff line number Diff line Loading @@ -243,6 +243,9 @@ long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv, long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc); int kgsl_cmdbatch_add_sync(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch, struct kgsl_cmd_syncpoint *sync); Loading Loading
drivers/gpu/msm/adreno.h +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #define KGSL_CMD_FLAGS_WFI BIT(2) #define KGSL_CMD_FLAGS_PROFILE BIT(3) #define KGSL_CMD_FLAGS_PWRON_FIXUP BIT(4) #define KGSL_CMD_FLAGS_MEMLIST BIT(5) /* Command identifiers */ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF Loading
drivers/gpu/msm/adreno_dispatch.c +4 −4 Original line number Diff line number Diff line Loading @@ -825,11 +825,11 @@ static void mark_guilty_context(struct kgsl_device *device, unsigned int id) static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base) { int i; struct kgsl_memobj_node *ib; for (i = 0; i < cmdbatch->ibcount; i++) { if (cmdbatch->ibdesc[i].gpuaddr == base) { cmdbatch->ibdesc[i].sizedwords = 0; list_for_each_entry(ib, &cmdbatch->cmdlist, node) { if (ib->gpuaddr == base) { ib->priv |= MEMOBJ_SKIP; if (base) return; } Loading
drivers/gpu/msm/adreno_ringbuffer.c +49 −46 Original line number Diff line number Diff line Loading @@ -1078,20 +1078,20 @@ done: * core does */ static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv, struct kgsl_ibdesc *ibdesc) struct kgsl_memobj_node *ib) { struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* Check that the size of the IBs is under the allowable limit */ if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) { if (ib->sizedwords == 0 || ib->sizedwords > 0xFFFFF) { KGSL_DRV_ERR(device, "Invalid IB size 0x%zX\n", ibdesc->sizedwords); ib->sizedwords); return false; } if (unlikely(adreno_dev->ib_check_level >= 1) && !_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) { !_parse_ibs(dev_priv, ib->gpuaddr, ib->sizedwords)) { KGSL_DRV_ERR(device, "Could not verify the IBs\n"); return false; } Loading @@ -1108,17 +1108,16 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, struct kgsl_device *device = dev_priv->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int i, ret; struct kgsl_memobj_node *ib; int ret; if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) return -EDEADLK; /* Verify the IBs before they get queued */ for (i = 0; i < cmdbatch->ibcount; i++) { if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i])) list_for_each_entry(ib, &cmdbatch->cmdlist, node) if (!_ringbuffer_verify_ib(dev_priv, ib)) return -EINVAL; } /* wait for the suspend gate */ wait_for_completion(&device->cmdbatch_gate); Loading Loading @@ -1210,22 +1209,22 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, struct kgsl_cmdbatch *cmdbatch) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_ibdesc *ibdesc; unsigned int numibs; struct kgsl_memobj_node *ib; unsigned int numibs = 0; unsigned int *link; unsigned int *cmds; unsigned int i; struct kgsl_context *context; struct adreno_context *drawctxt; unsigned int start_index = 0; bool use_preamble = true; int flags = KGSL_CMD_FLAGS_NONE; int ret; context = cmdbatch->context; drawctxt = ADRENO_CONTEXT(context); ibdesc = cmdbatch->ibdesc; numibs = cmdbatch->ibcount; /* Get the total IBs in the list */ list_for_each_entry(ib, &cmdbatch->cmdlist, node) numibs++; /* process any profiling results that are available into the log_buf */ adreno_profile_process_results(device); Loading Loading @@ -1260,7 +1259,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, if ((drawctxt->base.flags & KGSL_CONTEXT_PREAMBLE) && !test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) && (adreno_dev->drawctxt_active == drawctxt)) start_index = 1; use_preamble = false; /* * In skip mode don't issue the draw IBs but keep all the other Loading @@ -1268,43 +1267,47 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, * the accounting sane. Set start_index and numibs to 0 to just * generate the start and end markers and skip everything else */ if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) { start_index = 0; use_preamble = false; numibs = 0; } cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4), /* * Worst case size: * 2 - start of IB identifier * 1 - skip preamble * 3 * numibs - 3 per IB * 2 - end of IB identifier */ cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 5), GFP_KERNEL); if (!link) { ret = -ENOMEM; goto done; } if (!start_index) { *cmds++ = cp_nop_packet(1); *cmds++ = KGSL_START_OF_IB_IDENTIFIER; } else { *cmds++ = cp_nop_packet(4); *cmds++ = KGSL_START_OF_IB_IDENTIFIER; *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[0].gpuaddr; *cmds++ = ibdesc[0].sizedwords; } for (i = start_index; i < numibs; i++) { if (numibs) { list_for_each_entry(ib, &cmdbatch->cmdlist, node) { /* use the preamble? */ if ((ib->priv & MEMOBJ_PREAMBLE) && (use_preamble == false)) *cmds++ = cp_nop_packet(3); /* * Skip 0 sized IBs - these are presumed to have been removed * from consideration by the FT policy * Skip 0 sized IBs - these are presumed to have been * removed from consideration by the FT policy */ if (ibdesc[i].sizedwords == 0) if (ib->priv & MEMOBJ_SKIP) *cmds++ = cp_nop_packet(2); else *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = ibdesc[i].gpuaddr; *cmds++ = ibdesc[i].sizedwords; *cmds++ = ib->gpuaddr; *cmds++ = ib->sizedwords; } } *cmds++ = cp_nop_packet(1); Loading Loading @@ -1342,7 +1345,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, adreno_ringbuffer_set_constraint(device, cmdbatch); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); kgsl_cffdump_capture_ib_desc(device, context, cmdbatch); ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, drawctxt, Loading @@ -1355,8 +1358,8 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, 0x00000000, 0x80000000); done: trace_kgsl_issueibcmds(device, context->id, cmdbatch, cmdbatch->timestamp, cmdbatch->flags, ret, drawctxt->type); numibs, cmdbatch->timestamp, cmdbatch->flags, ret, drawctxt->type); kfree(link); return ret; Loading
drivers/gpu/msm/kgsl.c +129 −46 Original line number Diff line number Diff line Loading @@ -63,6 +63,12 @@ #define KGSL_DMA_BIT_MASK DMA_BIT_MASK(32) #endif /* * Define an kmem cache for the memobj structures since we allocate and free * them so frequently */ static struct kmem_cache *memobjs_cache; static char *ksgl_mmu_type; module_param_named(mmutype, ksgl_mmu_type, charp, 0); MODULE_PARM_DESC(ksgl_mmu_type, Loading Loading @@ -1461,7 +1467,6 @@ void kgsl_cmdbatch_destroy_object(struct kref *kref) struct kgsl_cmdbatch, refcount); kgsl_context_put(cmdbatch->context); kfree(cmdbatch->ibdesc); kfree(cmdbatch); } Loading Loading @@ -1533,6 +1538,17 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, kgsl_cmdbatch_sync_event_put(event); } static inline void _free_memobj_list(struct list_head *list) { struct kgsl_memobj_node *mem, *tmpmem; /* Free the cmd mem here */ list_for_each_entry_safe(mem, tmpmem, list, node) { list_del_init(&mem->node); kmem_cache_free(memobjs_cache, mem); } } /** * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure * @cmdbatch: Pointer to the command batch object to destroy Loading @@ -1543,7 +1559,7 @@ static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, */ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) { struct kgsl_cmdbatch_sync_event *event, *tmp; struct kgsl_cmdbatch_sync_event *event, *tmpsync; LIST_HEAD(cancel_synclist); int sched = 0; Loading @@ -1563,7 +1579,7 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) * not to signal the callback. This guarantee ensures that * the reference count for the event and cmdbatch is correct. */ list_for_each_entry_safe(event, tmp, &cancel_synclist, node) { list_for_each_entry_safe(event, tmpsync, &cancel_synclist, node) { sched = 1; if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) { Loading @@ -1585,6 +1601,12 @@ void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch) kgsl_cmdbatch_sync_event_put(event); } /* Destroy the cmdlist we created */ _free_memobj_list(&cmdbatch->cmdlist); /* Destroy the memlist we created */ _free_memobj_list(&cmdbatch->memlist); /* * If we cancelled an event, there's a good chance that the context is * on a dispatcher queue, so schedule to get it removed. Loading Loading @@ -1830,18 +1852,58 @@ int kgsl_cmdbatch_add_sync(struct kgsl_device *device, return ret; } /** * kgsl_cmdbatch_add_memobj() - Add an entry to a command batch * @cmdbatch: Pointer to the cmdbatch * @ibdesc: Pointer to the user-specified struct defining the memory or IB * @preamble: Flag to mark this ibdesc as a preamble (if known) * * Create a new memory entry in the cmdbatch based on the user specified * parameters */ int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc) { struct kgsl_memobj_node *mem; mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL); if (mem == NULL) return -ENOMEM; mem->gpuaddr = ibdesc->gpuaddr; mem->sizedwords = ibdesc->sizedwords; mem->priv = 0; /* sanitize the ibdesc ctrl flags */ ibdesc->ctrl &= KGSL_IBDESC_MEMLIST; if (cmdbatch->flags & KGSL_CMDBATCH_MEMLIST && ibdesc->ctrl & KGSL_IBDESC_MEMLIST) { /* add to the memlist */ list_add_tail(&mem->node, &cmdbatch->memlist); } else { /* set the preamble flag if directed to */ if (cmdbatch->context->flags & KGSL_CONTEXT_PREAMBLE && list_empty(&cmdbatch->cmdlist)) mem->priv = MEMOBJ_PREAMBLE; /* add to the cmd list */ list_add_tail(&mem->node, &cmdbatch->cmdlist); } return 0; } /** * kgsl_cmdbatch_create() - Create a new cmdbatch structure * @device: Pointer to a KGSL device struct * @context: Pointer to a KGSL context struct * @numibs: Number of indirect buffers to make room for in the cmdbatch * @flags: Flags for the cmdbatch * * Allocate an new cmdbatch structure and add enough room to store the list of * indirect buffers * Allocate an new cmdbatch structure */ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, struct kgsl_context *context, unsigned int flags, unsigned int numibs) struct kgsl_context *context, unsigned int flags) { struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL); if (cmdbatch == NULL) Loading @@ -1857,22 +1919,13 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, return ERR_PTR(-EINVAL); } if (!(flags & KGSL_CONTEXT_SYNC)) { cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs, GFP_KERNEL); if (cmdbatch->ibdesc == NULL) { kgsl_context_put(context); kfree(cmdbatch); return ERR_PTR(-ENOMEM); } } kref_init(&cmdbatch->refcount); INIT_LIST_HEAD(&cmdbatch->cmdlist); INIT_LIST_HEAD(&cmdbatch->synclist); INIT_LIST_HEAD(&cmdbatch->memlist); spin_lock_init(&cmdbatch->lock); cmdbatch->device = device; cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs; cmdbatch->context = context; cmdbatch->flags = flags & ~KGSL_CMDBATCH_SUBMIT_IB_LIST; Loading @@ -1895,27 +1948,27 @@ static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device, static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv, struct kgsl_cmdbatch *cmdbatch) { int i; struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_memobj_node *ib; for (i = 0; i < cmdbatch->ibcount; i++) { if (cmdbatch->ibdesc[i].sizedwords == 0) { list_for_each_entry(ib, &cmdbatch->cmdlist, node) { if (ib->sizedwords == 0) { KGSL_DRV_ERR(dev_priv->device, "invalid size ctx %d ib(%d) %lX/%zX\n", cmdbatch->context->id, i, cmdbatch->ibdesc[i].gpuaddr, cmdbatch->ibdesc[i].sizedwords); "invalid size ctx %d %lX/%zX\n", cmdbatch->context->id, ib->gpuaddr, ib->sizedwords); return false; } if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, cmdbatch->ibdesc[i].gpuaddr)) { ib->gpuaddr)) { KGSL_DRV_ERR(dev_priv->device, "Invalid address ctx %d ib(%d) %lX/%zX\n", cmdbatch->context->id, i, cmdbatch->ibdesc[i].gpuaddr, cmdbatch->ibdesc[i].sizedwords); "Invalid address ctx %d %lX/%zX\n", cmdbatch->context->id, ib->gpuaddr, ib->sizedwords); return false; } Loading @@ -1937,16 +1990,24 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy( struct kgsl_context *context, struct kgsl_ringbuffer_issueibcmds *param) { struct kgsl_memobj_node *mem; struct kgsl_cmdbatch *cmdbatch = kgsl_cmdbatch_create(device, context, param->flags, 1); kgsl_cmdbatch_create(device, context, param->flags); if (IS_ERR(cmdbatch)) return cmdbatch; cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr; cmdbatch->ibdesc[0].sizedwords = param->numibs; cmdbatch->ibcount = 1; cmdbatch->flags = param->flags; mem = kmem_cache_alloc(memobjs_cache, GFP_KERNEL); if (mem == NULL) { kgsl_cmdbatch_destroy(cmdbatch); return NULL; } mem->gpuaddr = param->ibdesc_addr; mem->sizedwords = param->numibs; mem->priv = 0; list_add_tail(&mem->node, &cmdbatch->cmdlist); return cmdbatch; } Loading @@ -1969,8 +2030,8 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device, void __user *synclist, unsigned int numsyncs) { struct kgsl_cmdbatch *cmdbatch = kgsl_cmdbatch_create(device, context, flags, numcmds); int ret = 0; kgsl_cmdbatch_create(device, context, flags); int ret = 0, i; if (IS_ERR(cmdbatch)) return cmdbatch; Loading @@ -1982,30 +2043,40 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device, } if (!(flags & KGSL_CMDBATCH_SYNC)) { if (copy_from_user(cmdbatch->ibdesc, cmdlist, sizeof(struct kgsl_ibdesc) * numcmds)) { struct kgsl_ibdesc ibdesc; void __user *uptr = cmdlist; for (i = 0; i < numcmds; i++) { memset(&ibdesc, 0, sizeof(ibdesc)); if (copy_from_user(&ibdesc, uptr, sizeof(ibdesc))) { ret = -EFAULT; goto done; } ret = kgsl_cmdbatch_add_memobj(cmdbatch, &ibdesc); if (ret) goto done; uptr += sizeof(ibdesc); } } if (synclist && numsyncs) { struct kgsl_cmd_syncpoint sync; void __user *uptr = synclist; int i; for (i = 0; i < numsyncs; i++) { memset(&sync, 0, sizeof(sync)); if (copy_from_user(&sync, uptr, sizeof(sync))) { ret = -EFAULT; break; goto done; } ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync); if (ret) break; goto done; uptr += sizeof(sync); } Loading Loading @@ -4282,6 +4353,10 @@ static void kgsl_core_exit(void) kgsl_driver.class = NULL; } /* free the memobject cache */ if (memobjs_cache) kmem_cache_destroy(memobjs_cache); kgsl_memfree_hist_exit(); unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX); } Loading Loading @@ -4352,6 +4427,14 @@ static int __init kgsl_core_init(void) kgsl_events_init(); /* create the memobjs kmem cache */ memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0); if (memobjs_cache == NULL) { KGSL_CORE_ERR("failed to create memobjs_cache"); result = -ENOMEM; goto err; } if (kgsl_memfree_hist_init()) KGSL_CORE_ERR("failed to init memfree_hist"); Loading
drivers/gpu/msm/kgsl.h +3 −0 Original line number Diff line number Diff line Loading @@ -243,6 +243,9 @@ long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv, long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); int kgsl_cmdbatch_add_memobj(struct kgsl_cmdbatch *cmdbatch, struct kgsl_ibdesc *ibdesc); int kgsl_cmdbatch_add_sync(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch, struct kgsl_cmd_syncpoint *sync); Loading