Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6603e7fe authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Make sure to synchronize RCUs before freeing sync events"

parents cbe50b5f e759b1c6
Loading
Loading
Loading
Loading
+8 −19
Original line number Diff line number Diff line
@@ -652,7 +652,7 @@ void adreno_cp_callback(struct adreno_device *adreno_dev, int bit)
{
	struct kgsl_device *device = &adreno_dev->dev;

	queue_work(device->work_queue, &device->event_work);
	kgsl_schedule_work(&device->event_work);
	adreno_dispatcher_schedule(device);
}

@@ -1315,24 +1315,13 @@ static int _adreno_start(struct adreno_device *adreno_dev)
		adreno_writereg(adreno_dev,
				ADRENO_REG_RBBM_SECVID_TSB_CONTROL, 0x0);

		if (ADRENO_FEATURE(adreno_dev, ADRENO_64BIT) &&
			MMU_FEATURE(&device->mmu, KGSL_MMU_64BIT)) {
		adreno_writereg64(adreno_dev,
			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
				KGSL_IOMMU_SECURE_BASE64);
			KGSL_IOMMU_SECURE_BASE);
		adreno_writereg(adreno_dev,
			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
				KGSL_IOMMU_SECURE_SIZE64);
		} else {
			adreno_writereg64(adreno_dev,
				ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
				ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
				KGSL_IOMMU_SECURE_BASE32);
			adreno_writereg(adreno_dev,
				ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
				KGSL_IOMMU_SECURE_SIZE32);
		}
			KGSL_IOMMU_SECURE_SIZE);
	}

	status = adreno_ocmem_malloc(adreno_dev);
+1 −1
Original line number Diff line number Diff line
@@ -2767,7 +2767,7 @@ static void a5xx_gpmu_int_callback(struct adreno_device *adreno_dev, int bit)
			/* Stop GPMU */
			kgsl_regwrite(device, A5XX_GPMU_CM3_SYSRESET, 1);

			queue_work(device->work_queue, &adreno_dev->gpmu_work);
			kgsl_schedule_work(&adreno_dev->gpmu_work);

			KGSL_DRV_CRIT_RATELIMIT(device,
						"GPMU: Watchdog bite\n");
+3 −3
Original line number Diff line number Diff line
@@ -2135,7 +2135,7 @@ static void adreno_dispatcher_work(struct work_struct *work)
	 * stragglers
	 */
	if (dispatcher->inflight == 0 && count)
		queue_work(device->work_queue, &device->event_work);
		kgsl_schedule_work(&device->event_work);

	/* Try to dispatch new commands */
	_adreno_dispatcher_issuecmds(adreno_dev);
@@ -2188,7 +2188,7 @@ void adreno_dispatcher_schedule(struct kgsl_device *device)
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;

	queue_work(device->work_queue, &dispatcher->work);
	kgsl_schedule_work(&dispatcher->work);
}

/**
@@ -2577,7 +2577,7 @@ void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev,
		cmdbatch->expires = jiffies +
			msecs_to_jiffies(adreno_cmdbatch_timeout);
	}
	queue_work(device->work_queue, &device->event_work);
	kgsl_schedule_work(&device->event_work);
}

/**
+45 −34
Original line number Diff line number Diff line
@@ -228,13 +228,24 @@ int kgsl_readtimestamp(struct kgsl_device *device, void *priv,
}
EXPORT_SYMBOL(kgsl_readtimestamp);

/* Scheduled by kgsl_mem_entry_put_deferred() */
static void _deferred_put(struct work_struct *work)
{
	struct kgsl_mem_entry *entry =
		container_of(work, struct kgsl_mem_entry, work);

	kgsl_mem_entry_put(entry);
}

static inline struct kgsl_mem_entry *
kgsl_mem_entry_create(void)
{
	struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);

	if (entry)
	if (entry != NULL) {
		kref_init(&entry->refcount);
		INIT_WORK(&entry->work, _deferred_put);
	}

	return entry;
}
@@ -1256,6 +1267,8 @@ kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
	int result = 0;
	struct kgsl_mem_entry *entry;

	drain_workqueue(kgsl_driver.mem_workqueue);

	spin_lock(&process->mem_lock);
	entry = idr_find(&process->mem_idr, id);
	if (entry)
@@ -1833,8 +1846,7 @@ static long gpuobj_free_on_timestamp(struct kgsl_device_private *dev_priv,

static void gpuobj_free_fence_func(void *priv)
{
	struct kgsl_mem_entry *entry = priv;
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred((struct kgsl_mem_entry *) priv);
}

static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
@@ -1844,15 +1856,22 @@ static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
	struct kgsl_gpu_event_fence event;
	long ret;

	if (!kgsl_mem_entry_set_pend(entry))
		return -EBUSY;

	memset(&event, 0, sizeof(event));

	ret = _copy_from_user(&event, to_user_ptr(param->priv),
		sizeof(event), param->len);
	if (ret)
	if (ret) {
		kgsl_mem_entry_unset_pend(entry);
		return ret;
	}

	if (event.fd < 0)
	if (event.fd < 0) {
		kgsl_mem_entry_unset_pend(entry);
		return -EINVAL;
	}

	handle = kgsl_sync_fence_async_wait(event.fd,
		gpuobj_free_fence_func, entry);
@@ -1861,7 +1880,12 @@ static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
	if (handle == NULL)
		return gpumem_free_entry(entry);

	return IS_ERR(handle) ? PTR_ERR(handle) : 0;
	if (IS_ERR(handle)) {
		kgsl_mem_entry_unset_pend(entry);
		return PTR_ERR(handle);
	}

	return 0;
}

long kgsl_ioctl_gpuobj_free(struct kgsl_device_private *dev_priv,
@@ -2386,7 +2410,7 @@ static int kgsl_setup_dma_buf(struct kgsl_device *device,
	entry->memdesc.size = 0;
	entry->memdesc.mmapsize = 0;
	/* USE_CPU_MAP is not impemented for ION. */
	entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
	entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
	entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ION;

	sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
@@ -2483,10 +2507,11 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
			| KGSL_MEMALIGN_MASK
			| KGSL_MEMFLAGS_USE_CPU_MAP
			| KGSL_MEMFLAGS_SECURE;
	entry->memdesc.flags = param->flags | KGSL_MEMFLAGS_FORCE_32BIT;
	entry->memdesc.flags = ((uint64_t) param->flags)
		| KGSL_MEMFLAGS_FORCE_32BIT;

	if (!kgsl_mmu_use_cpu_map(&dev_priv->device->mmu))
		entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
		entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);

	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
		entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE;
@@ -2865,7 +2890,7 @@ static uint64_t kgsl_filter_cachemode(uint64_t flags)
	 */
	if ((flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT ==
					KGSL_CACHEMODE_WRITETHROUGH) {
		flags &= ~KGSL_CACHEMODE_MASK;
		flags &= ~((uint64_t) KGSL_CACHEMODE_MASK);
		flags |= (KGSL_CACHEMODE_WRITEBACK << KGSL_CACHEMODE_SHIFT) &
							KGSL_CACHEMODE_MASK;
	}
@@ -2900,7 +2925,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry(

	/* Turn off SVM if the system doesn't support it */
	if (!kgsl_mmu_use_cpu_map(&dev_priv->device->mmu))
		flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
		flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);

	/* Return not supported error if secure memory isn't enabled */
	if (!kgsl_mmu_is_secured(&dev_priv->device->mmu) &&
@@ -2912,8 +2937,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry(

	/* Secure memory disables advanced addressing modes */
	if (flags & KGSL_MEMFLAGS_SECURE)
		flags &= ~(KGSL_MEMFLAGS_USE_CPU_MAP
			   | KGSL_MEMFLAGS_FORCE_32BIT);
		flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);

	/* Cap the alignment bits to the highest number we can handle */
	align = MEMFLAGS(flags, KGSL_MEMALIGN_MASK, KGSL_MEMALIGN_SHIFT);
@@ -2921,7 +2945,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry(
		KGSL_CORE_ERR("Alignment too large; restricting to %dK\n",
			KGSL_MAX_ALIGN >> 10);

		flags &= ~KGSL_MEMALIGN_MASK;
		flags &= ~((uint64_t) KGSL_MEMALIGN_MASK);
		flags |= (ilog2(KGSL_MAX_ALIGN) << KGSL_MEMALIGN_SHIFT) &
			KGSL_MEMALIGN_MASK;
	}
@@ -3023,7 +3047,7 @@ long kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
	uint64_t flags = param->flags;

	/* Legacy functions doesn't support these advanced features */
	flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
	flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
	flags |= KGSL_MEMFLAGS_FORCE_32BIT;

	entry = gpumem_alloc_entry(dev_priv, (uint64_t) param->size,
@@ -3145,7 +3169,7 @@ long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv,
		copy_metadata(entry, param->metadata, param->metadata_len);

	if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) {
		entry->memdesc.flags &= ~KGSL_MEMTYPE_MASK;
		entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
		entry->memdesc.flags |= param->type << KGSL_MEMTYPE_SHIFT;
	}

@@ -3882,20 +3906,10 @@ int kgsl_device_platform_probe(struct kgsl_device *device)

	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);

	/* Create our primary workqueue for events and power */
	device->work_queue = create_singlethread_workqueue(device->name);
	if (device->work_queue == NULL) {
		status = -ENODEV;
		KGSL_DRV_ERR(device,
			"create_singelthreaded_workqueue(%s) failed\n",
			device->name);
		goto error_pwrctrl_close;
	}

	status = kgsl_mmu_init(device);
	if (status != 0) {
		KGSL_DRV_ERR(device, "kgsl_mmu_init failed %d\n", status);
		goto error_dest_work_q;
		goto error_pwrctrl_close;
	}

	/* Check to see if our device can perform DMA correctly */
@@ -3946,9 +3960,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device)

error_close_mmu:
	kgsl_mmu_close(device);
error_dest_work_q:
	destroy_workqueue(device->work_queue);
	device->work_queue = NULL;
error_pwrctrl_close:
	kgsl_pwrctrl_close(device);
error:
@@ -3973,10 +3984,6 @@ void kgsl_device_platform_remove(struct kgsl_device *device)

	kgsl_mmu_close(device);

	if (device->work_queue) {
		destroy_workqueue(device->work_queue);
		device->work_queue = NULL;
	}
	kgsl_pwrctrl_close(device);

	_unregister_device(device);
@@ -4073,6 +4080,10 @@ static int __init kgsl_core_init(void)

	INIT_LIST_HEAD(&kgsl_driver.pagetable_list);

	kgsl_driver.workqueue = create_singlethread_workqueue("kgsl-workqueue");
	kgsl_driver.mem_workqueue =
		create_singlethread_workqueue("kgsl-mementry");

	kgsl_mmu_set_mmutype(ksgl_mmu_type);

	kgsl_events_init();
+47 −10
Original line number Diff line number Diff line
@@ -58,29 +58,38 @@ static inline void KGSL_STATS_ADD(uint64_t size, atomic_long_t *stat,
struct kgsl_device;
struct kgsl_context;

/**
 * struct kgsl_driver - main container for global KGSL things
 * @cdev: Character device struct
 * @major: Major ID for the KGSL device
 * @class: Pointer to the class struct for the core KGSL sysfs entries
 * @virtdev: Virtual device for managing the core
 * @ptkobj: kobject for storing the pagetable statistics
 * @prockobj: kobject for storing the process statistics
 * @devp: Array of pointers to the individual KGSL device structs
 * @process_list: List of open processes
 * @pagetable_list: LIst of open pagetables
 * @ptlock: Lock for accessing the pagetable list
 * @process_mutex: Mutex for accessing the process list
 * @devlock: Mutex protecting the device list
 * @stats: Struct containing atomic memory statistics
 * @full_cache_threshold: the threshold that triggers a full cache flush
 * @workqueue: Pointer to a single threaded workqueue
 * @mem_workqueue: Pointer to a workqueue for deferring memory entries
 */
struct kgsl_driver {
	struct cdev cdev;
	dev_t major;
	struct class *class;
	/* Virtual device for managing the core */
	struct device virtdev;
	/* Kobjects for storing pagetable and process statistics */
	struct kobject *ptkobj;
	struct kobject *prockobj;
	struct kgsl_device *devp[KGSL_DEVICE_MAX];

	/* Global lilst of open processes */
	struct list_head process_list;
	/* Global list of pagetables */
	struct list_head pagetable_list;
	/* Spinlock for accessing the pagetable list */
	spinlock_t ptlock;
	/* Mutex for accessing the process list */
	struct mutex process_mutex;

	/* Mutex for protecting the device list */
	struct mutex devlock;

	struct {
		atomic_long_t vmalloc;
		atomic_long_t vmalloc_max;
@@ -94,6 +103,8 @@ struct kgsl_driver {
		atomic_long_t mapped_max;
	} stats;
	unsigned int full_cache_threshold;
	struct workqueue_struct *workqueue;
	struct workqueue_struct *mem_workqueue;
};

extern struct kgsl_driver kgsl_driver;
@@ -190,6 +201,7 @@ struct kgsl_memdesc {
 *  are still references to it.
 * @dev_priv: back pointer to the device file that created this entry.
 * @metadata: String containing user specified metadata for the entry
 * @work: Work struct used to schedule a kgsl_mem_entry_put in atomic contexts
 */
struct kgsl_mem_entry {
	struct kref refcount;
@@ -200,6 +212,7 @@ struct kgsl_mem_entry {
	struct kgsl_process_private *priv;
	int pending_free;
	char metadata[KGSL_GPUOBJ_ALLOC_METADATA_MAX + 1];
	struct work_struct work;
};

struct kgsl_device_private;
@@ -410,6 +423,15 @@ static inline int timestamp_cmp(unsigned int a, unsigned int b)
	return ((a > b) && (a - b <= KGSL_TIMESTAMP_WINDOW)) ? 1 : -1;
}

/**
 * kgsl_schedule_work() - Schedule a work item on the KGSL workqueue
 * @work: work item to schedule
 */
static inline void kgsl_schedule_work(struct work_struct *work)
{
	queue_work(kgsl_driver.workqueue, work);
}

static inline int
kgsl_mem_entry_get(struct kgsl_mem_entry *entry)
{
@@ -422,6 +444,21 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry)
	kref_put(&entry->refcount, kgsl_mem_entry_destroy);
}

/**
 * kgsl_mem_entry_put_deferred() - Schedule a task to put the memory entry
 * @entry: Mem entry to put
 *
 * This function is for atomic contexts where a normal kgsl_mem_entry_put()
 * would result in the memory entry getting destroyed and possibly taking
 * mutexes along the way.  Schedule the work to happen outside of the atomic
 * context.
 */
static inline void kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry)
{
	if (entry != NULL)
		queue_work(kgsl_driver.mem_workqueue, &entry->work);
}

/*
 * kgsl_addr_range_overlap() - Checks if 2 ranges overlap
 * @gpuaddr1: Start of first address range
Loading