122 lines · 2.6 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/smp.h> #include <asm/mips_mt.h>#include <asm/vpe.h>#include <asm/rtlx.h> static int major; static void rtlx_interrupt(void){	int i;	struct rtlx_info *info;	struct rtlx_info **p = vpe_get_shared(aprp_cpu_index()); 	if (p == NULL || *p == NULL)		return; 	info = *p; 	if (info->ap_int_pending == 1 && smp_processor_id() == 0) {		for (i = 0; i < RTLX_CHANNELS; i++) {			wake_up(&channel_wqs[i].lx_queue);			wake_up(&channel_wqs[i].rt_queue);		}		info->ap_int_pending = 0;	}} void _interrupt_sp(void){	smp_send_reschedule(aprp_cpu_index());} 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 (num_possible_cpus() - aprp_cpu_index() < 1) {		pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"			"Pass maxcpus=<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_interrupt;	} else {		pr_err("APRP RTLX init on non-vectored-interrupt processor\n");		err = -ENODEV;		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;}