/*
 * Copyright 2014 Red Hat 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.
 *
 * Authors: Ben Skeggs <bskeggs@redhat.com>
 */
#include "priv.h"

#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/image.h>

struct shadow {
	u32 skip;
	const struct nvbios_source *func;
	void *data;
	u32 size;
	int score;
};

static bool
shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto)
{
	const u32 limit = (upto + 3) & ~3;
	const u32 start = bios->size;
	void *data = mthd->data;
	if (nvbios_extend(bios, limit) > 0) {
		u32 read = mthd->func->read(data, start, limit - start, bios);
		bios->size = start + read;
	}
	return bios->size >= upto;
}

static int
shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
{
	struct nvkm_subdev *subdev = &bios->subdev;
	struct nvbios_image image;
	int score = 1;

	if (mthd->func->no_pcir) {
		image.base = 0;
		image.type = 0;
		image.size = mthd->func->size(mthd->data);
		image.last = 1;
	} else {
		if (!shadow_fetch(bios, mthd, offset + 0x1000)) {
			nvkm_debug(subdev, "%08x: header fetch failed\n",
				   offset);
			return 0;
		}

		if (!nvbios_image(bios, idx, &image)) {
			nvkm_debug(subdev, "image %d invalid\n", idx);
			return 0;
		}
	}
	nvkm_debug(subdev, "%08x: type %02x, %d bytes\n",
		   image.base, image.type, image.size);

	if (!shadow_fetch(bios, mthd, image.size)) {
		nvkm_debug(subdev, "%08x: fetch failed\n", image.base);
		return 0;
	}

	switch (image.type) {
	case 0x00:
		if (!mthd->func->ignore_checksum &&
		    nvbios_checksum(&bios->data[image.base], image.size)) {
			nvkm_debug(subdev, "%08x: checksum failed\n",
				   image.base);
			if (!mthd->func->require_checksum) {
				if (mthd->func->rw)
					score += 1;
				score += 1;
			} else
				return 0;
		} else {
			score += 3;
		}
		break;
	default:
		score += 3;
		break;
	}

	if (!image.last)
		score += shadow_image(bios, idx + 1, offset + image.size, mthd);
	return score;
}

static int
shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name)
{
	const struct nvbios_source *func = mthd->func;
	struct nvkm_subdev *subdev = &bios->subdev;
	if (func->name) {
		nvkm_debug(subdev, "trying %s...\n", name ? name : func->name);
		if (func->init) {
			mthd->data = func->init(bios, name);
			if (IS_ERR(mthd->data)) {
				mthd->data = NULL;
				return 0;
			}
		}
		mthd->score = shadow_image(bios, 0, 0, mthd);
		if (func->fini)
			func->fini(mthd->data);
		nvkm_debug(subdev, "scored %d\n", mthd->score);
		mthd->data = bios->data;
		mthd->size = bios->size;
		bios->data  = NULL;
		bios->size  = 0;
	}
	return mthd->score;
}

static u32
shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
{
	const struct firmware *fw = data;
	if (offset + length <= fw->size) {
		memcpy(bios->data + offset, fw->data + offset, length);
		return length;
	}
	return 0;
}

static void *
shadow_fw_init(struct nvkm_bios *bios, const char *name)
{
	struct device *dev = bios->subdev.device->dev;
	const struct firmware *fw;
	int ret = request_firmware(&fw, name, dev);
	if (ret)
		return ERR_PTR(-ENOENT);
	return (void *)fw;
}

static const struct nvbios_source
shadow_fw = {
	.name = "firmware",
	.init = shadow_fw_init,
	.fini = (void(*)(void *))release_firmware,
	.read = shadow_fw_read,
	.rw = false,
};

int
nvbios_shadow(struct nvkm_bios *bios)
{
	struct nvkm_subdev *subdev = &bios->subdev;
	struct nvkm_device *device = subdev->device;
	struct shadow mthds[] = {
		{ 0, &nvbios_of },
		{ 0, &nvbios_ramin },
		{ 0, &nvbios_rom },
		{ 0, &nvbios_acpi_fast },
		{ 4, &nvbios_acpi_slow },
		{ 1, &nvbios_pcirom },
		{ 1, &nvbios_platform },
		{}
	}, *mthd, *best = NULL;
	const char *optarg;
	char *source;
	int optlen;

	/* handle user-specified bios source */
	optarg = nvkm_stropt(device->cfgopt, "NvBios", &optlen);
	source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
	if (source) {
		/* try to match one of the built-in methods */
		for (mthd = mthds; mthd->func; mthd++) {
			if (mthd->func->name &&
			    !strcasecmp(source, mthd->func->name)) {
				best = mthd;
				if (shadow_method(bios, mthd, NULL))
					break;
			}
		}

		/* otherwise, attempt to load as firmware */
		if (!best && (best = mthd)) {
			mthd->func = &shadow_fw;
			shadow_method(bios, mthd, source);
			mthd->func = NULL;
		}

		if (!best->score) {
			nvkm_error(subdev, "%s invalid\n", source);
			kfree(source);
			source = NULL;
		}
	}

	/* scan all potential bios sources, looking for best image */
	if (!best || !best->score) {
		for (mthd = mthds, best = mthd; mthd->func; mthd++) {
			if (!mthd->skip || best->score < mthd->skip) {
				if (shadow_method(bios, mthd, NULL)) {
					if (mthd->score > best->score)
						best = mthd;
				}
			}
		}
	}

	/* cleanup the ones we didn't use */
	for (mthd = mthds; mthd->func; mthd++) {
		if (mthd != best)
			kfree(mthd->data);
	}

	if (!best->score) {
		nvkm_error(subdev, "unable to locate usable image\n");
		return -EINVAL;
	}

	nvkm_debug(subdev, "using image from %s\n", best->func ?
		   best->func->name : source);
	bios->data = best->data;
	bios->size = best->size;
	kfree(source);
	return 0;
}
