drivers/accel/habanalabs/common/memory.c

Source file repositories/reference/linux-study-clean/drivers/accel/habanalabs/common/memory.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/habanalabs/common/memory.c
Extension
.c
Size
81462 bytes
Lines
2939
Domain
Driver Families
Bucket
drivers/accel
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!is_power_of_2(psize)) {
			dev_err(hdev->dev, "user page size (%#llx) is not power of 2\n", psize);
			return -EINVAL;
		}
	} else {
		psize = prop->device_mem_alloc_default_page_size;
	}

	*page_size = psize;

	return 0;
}

/*
 * The va ranges in context object contain a list with the available chunks of
 * device virtual memory.
 * There is one range for host allocations and one for DRAM allocations.
 *
 * On initialization each range contains one chunk of all of its available
 * virtual range which is a half of the total device virtual range.
 *
 * On each mapping of physical pages, a suitable virtual range chunk (with a
 * minimum size) is selected from the list. If the chunk size equals the
 * requested size, the chunk is returned. Otherwise, the chunk is split into
 * two chunks - one to return as result and a remainder to stay in the list.
 *
 * On each Unmapping of a virtual address, the relevant virtual chunk is
 * returned to the list. The chunk is added to the list and if its edges match
 * the edges of the adjacent chunks (means a contiguous chunk can be created),
 * the chunks are merged.
 *
 * On finish, the list is checked to have only one chunk of all the relevant
 * virtual range (which is a half of the device total virtual range).
 * If not (means not all mappings were unmapped), a warning is printed.
 */

/*
 * alloc_device_memory() - allocate device memory.
 * @ctx: pointer to the context structure.
 * @args: host parameters containing the requested size.
 * @ret_handle: result handle.
 *
 * This function does the following:
 * - Allocate the requested size rounded up to 'dram_page_size' pages.
 * - Return unique handle for later map/unmap/free.
 */
static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
				u32 *ret_handle)
{
	struct hl_device *hdev = ctx->hdev;
	struct hl_vm *vm = &hdev->vm;
	struct hl_vm_phys_pg_pack *phys_pg_pack;
	u64 paddr = 0, total_size, num_pgs, i;
	u32 num_curr_pgs, page_size;
	bool contiguous;
	int handle, rc;

	num_curr_pgs = 0;

	rc = set_alloc_page_size(hdev, args, &page_size);
	if (rc)
		return rc;

	num_pgs = DIV_ROUND_UP_ULL(args->alloc.mem_size, page_size);
	total_size = num_pgs * page_size;

	if (!total_size) {
		dev_err(hdev->dev, "Cannot allocate 0 bytes\n");
		return -EINVAL;
	}

	contiguous = args->flags & HL_MEM_CONTIGUOUS;

	if (contiguous) {
		if (is_power_of_2(page_size))
			paddr = (uintptr_t) gen_pool_dma_alloc_align(vm->dram_pg_pool,
								     total_size, NULL, page_size);
		else
			paddr = gen_pool_alloc(vm->dram_pg_pool, total_size);
		if (!paddr) {
			dev_err(hdev->dev,
				"Cannot allocate %llu contiguous pages with total size of %llu\n",
				num_pgs, total_size);
			return -ENOMEM;
		}
	}

	phys_pg_pack = kzalloc_obj(*phys_pg_pack);
	if (!phys_pg_pack) {
		rc = -ENOMEM;

Annotation

Implementation Notes