arch/s390/include/asm/idals.h

Source file repositories/reference/linux-study-clean/arch/s390/include/asm/idals.h

File Facts

System
Linux kernel
Corpus path
arch/s390/include/asm/idals.h
Extension
.h
Size
7865 bytes
Lines
337
Domain
Architecture Layer
Bucket
arch/s390
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct idal_buffer {
	size_t size;
	size_t page_order;
	dma64_t data[];
};

/*
 * Allocate an idal buffer
 */
static inline struct idal_buffer *idal_buffer_alloc(size_t size, int page_order)
{
	int nr_chunks, nr_ptrs, i;
	struct idal_buffer *ib;
	void *vaddr;

	nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
	nr_chunks = (PAGE_SIZE << page_order) >> IDA_SIZE_SHIFT;
	ib = kmalloc_flex(*ib, data, nr_ptrs, GFP_DMA | GFP_KERNEL);
	if (!ib)
		return ERR_PTR(-ENOMEM);
	ib->size = size;
	ib->page_order = page_order;
	for (i = 0; i < nr_ptrs; i++) {
		if (i & (nr_chunks - 1)) {
			ib->data[i] = dma64_add(ib->data[i - 1], IDA_BLOCK_SIZE);
			continue;
		}
		vaddr = (void *)__get_free_pages(GFP_KERNEL, page_order);
		if (!vaddr)
			goto error;
		ib->data[i] = virt_to_dma64(vaddr);
	}
	return ib;
error:
	while (i >= nr_chunks) {
		i -= nr_chunks;
		vaddr = dma64_to_virt(ib->data[i]);
		free_pages((unsigned long)vaddr, ib->page_order);
	}
	kfree(ib);
	return ERR_PTR(-ENOMEM);
}

/*
 * Free an idal buffer.
 */
static inline void idal_buffer_free(struct idal_buffer *ib)
{
	int nr_chunks, nr_ptrs, i;
	void *vaddr;

	nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
	nr_chunks = (PAGE_SIZE << ib->page_order) >> IDA_SIZE_SHIFT;
	for (i = 0; i < nr_ptrs; i += nr_chunks) {
		vaddr = dma64_to_virt(ib->data[i]);
		free_pages((unsigned long)vaddr, ib->page_order);
	}
	kfree(ib);
}

/*
 * Allocate an array of IDAL buffers to cover a total data size of @size. The
 * resulting array is null-terminated.
 *
 * The amount of individual IDAL buffers is determined based on @size.
 * Each IDAL buffer can have a maximum size of @CCW_MAX_BYTE_COUNT.
 */
static inline struct idal_buffer **idal_buffer_array_alloc(size_t size, int page_order)
{
	struct idal_buffer **ibs;
	size_t ib_size; /* Size of a single idal buffer */
	int count; /* Amount of individual idal buffers */
	int i;

	count = (size + CCW_MAX_BYTE_COUNT - 1) / CCW_MAX_BYTE_COUNT;
	ibs = kmalloc_objs(*ibs, count + 1);
	for (i = 0; i < count; i++) {
		/* Determine size for the current idal buffer */
		ib_size = min(size, CCW_MAX_BYTE_COUNT);
		size -= ib_size;
		ibs[i] = idal_buffer_alloc(ib_size, page_order);
		if (IS_ERR(ibs[i])) {
			while (i--)
				idal_buffer_free(ibs[i]);
			kfree(ibs);
			ibs = NULL;
			return ERR_PTR(-ENOMEM);
		}
	}
	ibs[i] = NULL;

Annotation

Implementation Notes