/*
 * \brief  Implementation of linux/gfp.h
 * \author Norman Feske
 * \date   2015-09-09
 */

/*
 * Copyright (C) 2015-2017 Genode Labs GmbH
 *
 * This file is distributed under the terms of the GNU General Public License
 * version 2.
 */

/* Linux kit includes */
#include <lx_kit/addr_to_page_mapping.h>
#include <lx_kit/backend_alloc.h>
#include <lx_kit/malloc.h>
#include <lx_kit/env.h>


struct page *alloc_pages(gfp_t const gfp_mask, unsigned int order)
{
	using Genode::Cache_attribute;

	struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);

	size_t size = PAGE_SIZE << order;

	gfp_t const dma_mask = (GFP_DMA | GFP_LX_DMA | GFP_DMA32);
	Cache_attribute const cached = (gfp_mask & dma_mask) ? Genode::UNCACHED
	                                                     : Genode::CACHED;
	Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, cached);
	page->addr = Lx_kit::env().rm().attach(ds_cap);
	page->paddr = Genode::Dataspace_client(ds_cap).phys_addr();

	if (!page->addr) {
		Genode::error("alloc_pages: ", size, " failed");
		kfree(page);
		return 0;
	}

	Lx::Addr_to_page_mapping::insert(page, ds_cap);

	return page;
}


void free_pages(unsigned long addr, unsigned int order)
{
	page * page = Lx::Addr_to_page_mapping::find_page(addr);
	if (!page) return;

	Genode::Ram_dataspace_capability cap =
		Lx::Addr_to_page_mapping::remove(page);
	if (cap.valid())
		Lx::backend_free(cap);
	kfree(page);
}


void get_page(struct page *page)
{
	atomic_inc(&page->_count);
}


void put_page(struct page *page)
{
	TRACE;
}
