/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
 * Copyright (C) 2013 Imagination Technologies Ltd.
 */
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>

#include <asm/mips_mt.h>
#include <asm/vpe.h>
#include <asm/rtlx.h>

static int major;

static void rtlx_dispatch(void)
{
	if (read_c0_cause() & read_c0_status() & C_SW0)
		do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
}

/*
 * Interrupt handler may be called before rtlx_init has otherwise had
 * a chance to run.
 */
static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
{
	unsigned int vpeflags;
	unsigned long flags;
	int i;

	local_irq_save(flags);
	vpeflags = dvpe();
	set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ);
	irq_enable_hazard();
	evpe(vpeflags);
	local_irq_restore(flags);

	for (i = 0; i < RTLX_CHANNELS; i++) {
		wake_up(&channel_wqs[i].lx_queue);
		wake_up(&channel_wqs[i].rt_queue);
	}

	return IRQ_HANDLED;
}

static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;

void _interrupt_sp(void)
{
	unsigned long flags;

	local_irq_save(flags);
	dvpe();
	settc(1);
	write_vpe_c0_cause(read_vpe_c0_cause() | C_SW0);
	evpe(EVPE_ENABLE);
	local_irq_restore(flags);
}

int __init rtlx_module_init(void)
{
	struct device *dev;
	int i, err;

	if (!cpu_has_mipsmt) {
		pr_warn("VPE loader: not a MIPS MT capable processor\n");
		return -ENODEV;
	}

	if (aprp_cpu_index() == 0) {
		pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"
			"Pass maxtcs=<n> argument as kernel argument\n");

		return -ENODEV;
	}

	major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops);
	if (major < 0) {
		pr_err("rtlx_module_init: unable to register device\n");
		return major;
	}

	/* initialise the wait queues */
	for (i = 0; i < RTLX_CHANNELS; i++) {
		init_waitqueue_head(&channel_wqs[i].rt_queue);
		init_waitqueue_head(&channel_wqs[i].lx_queue);
		atomic_set(&channel_wqs[i].in_open, 0);
		mutex_init(&channel_wqs[i].mutex);

		dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
				    "%s%d", RTLX_MODULE_NAME, i);
		if (IS_ERR(dev)) {
			while (i--)
				device_destroy(mt_class, MKDEV(major, i));

			err = PTR_ERR(dev);
			goto out_chrdev;
		}
	}

	/* set up notifiers */
	rtlx_notify.start = rtlx_starting;
	rtlx_notify.stop = rtlx_stopping;
	vpe_notify(aprp_cpu_index(), &rtlx_notify);

	if (cpu_has_vint) {
		aprp_hook = rtlx_dispatch;
	} else {
		pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
		err = -ENODEV;
		goto out_class;
	}

	err = request_irq(rtlx_irq_num, rtlx_interrupt, 0, "RTLX", rtlx);
	if (err)
		goto out_class;

	return 0;

out_class:
	for (i = 0; i < RTLX_CHANNELS; i++)
		device_destroy(mt_class, MKDEV(major, i));
out_chrdev:
	unregister_chrdev(major, RTLX_MODULE_NAME);

	return err;
}

void __exit rtlx_module_exit(void)
{
	int i;

	for (i = 0; i < RTLX_CHANNELS; i++)
		device_destroy(mt_class, MKDEV(major, i));

	unregister_chrdev(major, RTLX_MODULE_NAME);

	aprp_hook = NULL;
}
