/*
 * 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.base + 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_prom },
		{ 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;
}
