Ricardo B. Marlieremips: mt: make mt_class constante5d95922 years agoHistory
147 lines · 3.2 KB · C
RawDownload
/* * 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;}