/*
 * Copyright 2014 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/**
 * \file amdgpu_device.c
 *
 *  Implementation of functions for AMD GPU device
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "xf86drm.h"
#include "amdgpu_drm.h"
#include "amdgpu_internal.h"
#include "util_hash_table.h"
#include "util_math.h"

#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
#define UINT_TO_PTR(x) ((void *)((intptr_t)(x)))

static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct util_hash_table *fd_tab;

static unsigned handle_hash(void *key)
{
	return PTR_TO_UINT(key);
}

static int handle_compare(void *key1, void *key2)
{
	return PTR_TO_UINT(key1) != PTR_TO_UINT(key2);
}

static unsigned fd_hash(void *key)
{
	int fd = PTR_TO_UINT(key);
	char *name = drmGetPrimaryDeviceNameFromFd(fd);
	unsigned result = 0;
	char *c;

	if (name == NULL)
		return 0;

	for (c = name; *c; ++c)
		result += *c;

	free(name);

	return result;
}

static int fd_compare(void *key1, void *key2)
{
	int fd1 = PTR_TO_UINT(key1);
	int fd2 = PTR_TO_UINT(key2);
	char *name1 = drmGetPrimaryDeviceNameFromFd(fd1);
	char *name2 = drmGetPrimaryDeviceNameFromFd(fd2);
	int result;

	if (name1 == NULL || name2 == NULL) {
		free(name1);
		free(name2);
		return 0;
	}

	result = strcmp(name1, name2);
	free(name1);
	free(name2);

	return result;
}

/**
* Get the authenticated form fd,
*
* \param   fd   - \c [in]  File descriptor for AMD GPU device
* \param   auth - \c [out] Pointer to output the fd is authenticated or not
*                          A render node fd, output auth = 0
*                          A legacy fd, get the authenticated for compatibility root
*
* \return   0 on success\n
*          >0 - AMD specific error code\n
*          <0 - Negative POSIX Error code
*/
static int amdgpu_get_auth(int fd, int *auth)
{
	int r = 0;
	drm_client_t client = {};

	if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER)
		*auth = 0;
	else {
		client.idx = 0;
		r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client);
		if (!r)
			*auth = client.auth;
	}
	return r;
}

static void amdgpu_device_free_internal(amdgpu_device_handle dev)
{
	amdgpu_vamgr_deinit(dev->vamgr);
	free(dev->vamgr);
	amdgpu_vamgr_deinit(dev->vamgr_32);
	free(dev->vamgr_32);
	util_hash_table_destroy(dev->bo_flink_names);
	util_hash_table_destroy(dev->bo_handles);
	pthread_mutex_destroy(&dev->bo_table_mutex);
	util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd));
	close(dev->fd);
	if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd))
		close(dev->flink_fd);
	free(dev);
}

/**
 * Assignment between two amdgpu_device pointers with reference counting.
 *
 * Usage:
 *    struct amdgpu_device *dst = ... , *src = ...;
 *
 *    dst = src;
 *    // No reference counting. Only use this when you need to move
 *    // a reference from one pointer to another.
 *
 *    amdgpu_device_reference(&dst, src);
 *    // Reference counters are updated. dst is decremented and src is
 *    // incremented. dst is freed if its reference counter is 0.
 */
static void amdgpu_device_reference(struct amdgpu_device **dst,
			     struct amdgpu_device *src)
{
	if (update_references(&(*dst)->refcount, &src->refcount))
		amdgpu_device_free_internal(*dst);
	*dst = src;
}

int amdgpu_device_initialize(int fd,
			     uint32_t *major_version,
			     uint32_t *minor_version,
			     amdgpu_device_handle *device_handle)
{
	struct amdgpu_device *dev;
	drmVersionPtr version;
	int r;
	int flag_auth = 0;
	int flag_authexist=0;
	uint32_t accel_working = 0;
	uint64_t start, max;

	*device_handle = NULL;

	pthread_mutex_lock(&fd_mutex);
	if (!fd_tab)
		fd_tab = util_hash_table_create(fd_hash, fd_compare);
	r = amdgpu_get_auth(fd, &flag_auth);
	if (r) {
		pthread_mutex_unlock(&fd_mutex);
		return r;
	}
	dev = util_hash_table_get(fd_tab, UINT_TO_PTR(fd));
	if (dev) {
		r = amdgpu_get_auth(dev->fd, &flag_authexist);
		if (r) {
			pthread_mutex_unlock(&fd_mutex);
			return r;
		}
		if ((flag_auth) && (!flag_authexist)) {
			dev->flink_fd = dup(fd);
		}
		*major_version = dev->major_version;
		*minor_version = dev->minor_version;
		amdgpu_device_reference(device_handle, dev);
		pthread_mutex_unlock(&fd_mutex);
		return 0;
	}

	dev = calloc(1, sizeof(struct amdgpu_device));
	if (!dev) {
		pthread_mutex_unlock(&fd_mutex);
		return -ENOMEM;
	}

	dev->fd = -1;
	dev->flink_fd = -1;

	atomic_set(&dev->refcount, 1);

	version = drmGetVersion(fd);
	if (version->version_major != 3) {
		fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is "
			"only compatible with 3.x.x.\n",
			__func__,
			version->version_major,
			version->version_minor,
			version->version_patchlevel);
		drmFreeVersion(version);
		r = -EBADF;
		goto cleanup;
	}

	dev->fd = dup(fd);
	dev->flink_fd = dev->fd;
	dev->major_version = version->version_major;
	dev->minor_version = version->version_minor;
	drmFreeVersion(version);

	dev->bo_flink_names = util_hash_table_create(handle_hash,
						     handle_compare);
	dev->bo_handles = util_hash_table_create(handle_hash, handle_compare);
	pthread_mutex_init(&dev->bo_table_mutex, NULL);

	/* Check if acceleration is working. */
	r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working);
	if (r)
		goto cleanup;
	if (!accel_working) {
		r = -EBADF;
		goto cleanup;
	}

	r = amdgpu_query_gpu_info_init(dev);
	if (r)
		goto cleanup;

	dev->vamgr = calloc(1, sizeof(struct amdgpu_bo_va_mgr));
	if (dev->vamgr == NULL)
		goto cleanup;

	amdgpu_vamgr_init(dev->vamgr, dev->dev_info.virtual_address_offset,
			  dev->dev_info.virtual_address_max,
			  dev->dev_info.virtual_address_alignment);

	max = MIN2(dev->dev_info.virtual_address_max, 0xffffffff);
	start = amdgpu_vamgr_find_va(dev->vamgr,
				     max - dev->dev_info.virtual_address_offset,
				     dev->dev_info.virtual_address_alignment, 0);
	if (start > 0xffffffff)
		goto free_va; /* shouldn't get here */

	dev->vamgr_32 =  calloc(1, sizeof(struct amdgpu_bo_va_mgr));
	if (dev->vamgr_32 == NULL)
		goto free_va;
	amdgpu_vamgr_init(dev->vamgr_32, start, max,
			  dev->dev_info.virtual_address_alignment);

	*major_version = dev->major_version;
	*minor_version = dev->minor_version;
	*device_handle = dev;
	util_hash_table_set(fd_tab, UINT_TO_PTR(dev->fd), dev);
	pthread_mutex_unlock(&fd_mutex);

	return 0;

free_va:
	r = -ENOMEM;
	amdgpu_vamgr_free_va(dev->vamgr, start,
			     max - dev->dev_info.virtual_address_offset);
	amdgpu_vamgr_deinit(dev->vamgr);
	free(dev->vamgr);

cleanup:
	if (dev->fd >= 0)
		close(dev->fd);
	free(dev);
	pthread_mutex_unlock(&fd_mutex);
	return r;
}

int amdgpu_device_deinitialize(amdgpu_device_handle dev)
{
	amdgpu_device_reference(&dev, NULL);
	return 0;
}
