aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd
diff options
context:
space:
mode:
authorOded Gabbay <oded.gabbay@amd.com>2014-10-27 08:36:07 -0400
committerOded Gabbay <oded.gabbay@amd.com>2015-01-09 15:26:08 -0500
commit6e81090b2ec4db256b08fab232e0d247aadf1bc5 (patch)
treee2d5e6ea301d49ac4a12badda4c3d69226ee5e82 /drivers/gpu/drm/amd
parent36b5c08f099a7b4d72a08784ab3efff592de2463 (diff)
drm/amdkfd: Add kfd gtt sub-allocator functions
This patch adds new kfd gtt sub-allocator functions that service the amdkfd driver when it wants to use gtt memory. The sub-allocator uses a bitmap to handle the memory area that was transferred to it during init. It divides the memory area into chunks, according to chunk size parameter. The allocation function will allocate contiguous chunks from that memory area, according to the requested size. If the requested size is smaller than the chunk size, a single chunk will be allocated. v2: Do some more verifications on parameters that are passed into kfd_gtt_sa_init() Signed-off-by: Oded Gabbay <oded.gabbay@amd.com> Reviewed-by: Alexey Skidanov <Alexey.skidanov@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c186
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h7
2 files changed, 193 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 436c31ca7710..33c30dc21d67 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -67,6 +67,10 @@ static const struct kfd_deviceid supported_devices[] = {
67 { 0x131D, &kaveri_device_info }, /* Kaveri */ 67 { 0x131D, &kaveri_device_info }, /* Kaveri */
68}; 68};
69 69
70static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
71 unsigned int chunk_size);
72static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
73
70static const struct kfd_device_info *lookup_device_info(unsigned short did) 74static const struct kfd_device_info *lookup_device_info(unsigned short did)
71{ 75{
72 size_t i; 76 size_t i;
@@ -307,3 +311,185 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
307 spin_unlock(&kfd->interrupt_lock); 311 spin_unlock(&kfd->interrupt_lock);
308 } 312 }
309} 313}
314
315static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
316 unsigned int chunk_size)
317{
318 unsigned int num_of_bits;
319
320 BUG_ON(!kfd);
321 BUG_ON(!kfd->gtt_mem);
322 BUG_ON(buf_size < chunk_size);
323 BUG_ON(buf_size == 0);
324 BUG_ON(chunk_size == 0);
325
326 kfd->gtt_sa_chunk_size = chunk_size;
327 kfd->gtt_sa_num_of_chunks = buf_size / chunk_size;
328
329 num_of_bits = kfd->gtt_sa_num_of_chunks / BITS_PER_BYTE;
330 BUG_ON(num_of_bits == 0);
331
332 kfd->gtt_sa_bitmap = kzalloc(num_of_bits, GFP_KERNEL);
333
334 if (!kfd->gtt_sa_bitmap)
335 return -ENOMEM;
336
337 pr_debug("kfd: gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p\n",
338 kfd->gtt_sa_num_of_chunks, kfd->gtt_sa_bitmap);
339
340 mutex_init(&kfd->gtt_sa_lock);
341
342 return 0;
343
344}
345
346static void kfd_gtt_sa_fini(struct kfd_dev *kfd)
347{
348 mutex_destroy(&kfd->gtt_sa_lock);
349 kfree(kfd->gtt_sa_bitmap);
350}
351
352static inline uint64_t kfd_gtt_sa_calc_gpu_addr(uint64_t start_addr,
353 unsigned int bit_num,
354 unsigned int chunk_size)
355{
356 return start_addr + bit_num * chunk_size;
357}
358
359static inline uint32_t *kfd_gtt_sa_calc_cpu_addr(void *start_addr,
360 unsigned int bit_num,
361 unsigned int chunk_size)
362{
363 return (uint32_t *) ((uint64_t) start_addr + bit_num * chunk_size);
364}
365
366int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
367 struct kfd_mem_obj **mem_obj)
368{
369 unsigned int found, start_search, cur_size;
370
371 BUG_ON(!kfd);
372
373 if (size == 0)
374 return -EINVAL;
375
376 if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size)
377 return -ENOMEM;
378
379 *mem_obj = kmalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
380 if ((*mem_obj) == NULL)
381 return -ENOMEM;
382
383 pr_debug("kfd: allocated mem_obj = %p for size = %d\n", *mem_obj, size);
384
385 start_search = 0;
386
387 mutex_lock(&kfd->gtt_sa_lock);
388
389kfd_gtt_restart_search:
390 /* Find the first chunk that is free */
391 found = find_next_zero_bit(kfd->gtt_sa_bitmap,
392 kfd->gtt_sa_num_of_chunks,
393 start_search);
394
395 pr_debug("kfd: found = %d\n", found);
396
397 /* If there wasn't any free chunk, bail out */
398 if (found == kfd->gtt_sa_num_of_chunks)
399 goto kfd_gtt_no_free_chunk;
400
401 /* Update fields of mem_obj */
402 (*mem_obj)->range_start = found;
403 (*mem_obj)->range_end = found;
404 (*mem_obj)->gpu_addr = kfd_gtt_sa_calc_gpu_addr(
405 kfd->gtt_start_gpu_addr,
406 found,
407 kfd->gtt_sa_chunk_size);
408 (*mem_obj)->cpu_ptr = kfd_gtt_sa_calc_cpu_addr(
409 kfd->gtt_start_cpu_ptr,
410 found,
411 kfd->gtt_sa_chunk_size);
412
413 pr_debug("kfd: gpu_addr = %p, cpu_addr = %p\n",
414 (uint64_t *) (*mem_obj)->gpu_addr, (*mem_obj)->cpu_ptr);
415
416 /* If we need only one chunk, mark it as allocated and get out */
417 if (size <= kfd->gtt_sa_chunk_size) {
418 pr_debug("kfd: single bit\n");
419 set_bit(found, kfd->gtt_sa_bitmap);
420 goto kfd_gtt_out;
421 }
422
423 /* Otherwise, try to see if we have enough contiguous chunks */
424 cur_size = size - kfd->gtt_sa_chunk_size;
425 do {
426 (*mem_obj)->range_end =
427 find_next_zero_bit(kfd->gtt_sa_bitmap,
428 kfd->gtt_sa_num_of_chunks, ++found);
429 /*
430 * If next free chunk is not contiguous than we need to
431 * restart our search from the last free chunk we found (which
432 * wasn't contiguous to the previous ones
433 */
434 if ((*mem_obj)->range_end != found) {
435 start_search = found;
436 goto kfd_gtt_restart_search;
437 }
438
439 /*
440 * If we reached end of buffer, bail out with error
441 */
442 if (found == kfd->gtt_sa_num_of_chunks)
443 goto kfd_gtt_no_free_chunk;
444
445 /* Check if we don't need another chunk */
446 if (cur_size <= kfd->gtt_sa_chunk_size)
447 cur_size = 0;
448 else
449 cur_size -= kfd->gtt_sa_chunk_size;
450
451 } while (cur_size > 0);
452
453 pr_debug("kfd: range_start = %d, range_end = %d\n",
454 (*mem_obj)->range_start, (*mem_obj)->range_end);
455
456 /* Mark the chunks as allocated */
457 for (found = (*mem_obj)->range_start;
458 found <= (*mem_obj)->range_end;
459 found++)
460 set_bit(found, kfd->gtt_sa_bitmap);
461
462kfd_gtt_out:
463 mutex_unlock(&kfd->gtt_sa_lock);
464 return 0;
465
466kfd_gtt_no_free_chunk:
467 pr_debug("kfd: allocation failed with mem_obj = %p\n", mem_obj);
468 mutex_unlock(&kfd->gtt_sa_lock);
469 kfree(mem_obj);
470 return -ENOMEM;
471}
472
473int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj)
474{
475 unsigned int bit;
476
477 BUG_ON(!kfd);
478 BUG_ON(!mem_obj);
479
480 pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n",
481 mem_obj, mem_obj->range_start, mem_obj->range_end);
482
483 mutex_lock(&kfd->gtt_sa_lock);
484
485 /* Mark the chunks as free */
486 for (bit = mem_obj->range_start;
487 bit <= mem_obj->range_end;
488 bit++)
489 clear_bit(bit, kfd->gtt_sa_bitmap);
490
491 mutex_unlock(&kfd->gtt_sa_lock);
492
493 kfree(mem_obj);
494 return 0;
495}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 2be9405bea1d..a79c21781d3b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -518,6 +518,13 @@ unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
518 struct kfd_process *process, 518 struct kfd_process *process,
519 unsigned int queue_id); 519 unsigned int queue_id);
520 520
521/* GTT Sub-Allocator */
522
523int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
524 struct kfd_mem_obj **mem_obj);
525
526int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj);
527
521extern struct device *kfd_device; 528extern struct device *kfd_device;
522 529
523/* Topology */ 530/* Topology */