Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
0007  * Copyright (C) 2013 Imagination Technologies Ltd.
0008  */
0009 #include <linux/device.h>
0010 #include <linux/fs.h>
0011 #include <linux/err.h>
0012 #include <linux/wait.h>
0013 #include <linux/sched.h>
0014 #include <linux/smp.h>
0015 
0016 #include <asm/mips_mt.h>
0017 #include <asm/vpe.h>
0018 #include <asm/rtlx.h>
0019 
0020 static int major;
0021 
0022 static void rtlx_interrupt(void)
0023 {
0024     int i;
0025     struct rtlx_info *info;
0026     struct rtlx_info **p = vpe_get_shared(aprp_cpu_index());
0027 
0028     if (p == NULL || *p == NULL)
0029         return;
0030 
0031     info = *p;
0032 
0033     if (info->ap_int_pending == 1 && smp_processor_id() == 0) {
0034         for (i = 0; i < RTLX_CHANNELS; i++) {
0035             wake_up(&channel_wqs[i].lx_queue);
0036             wake_up(&channel_wqs[i].rt_queue);
0037         }
0038         info->ap_int_pending = 0;
0039     }
0040 }
0041 
0042 void _interrupt_sp(void)
0043 {
0044     smp_send_reschedule(aprp_cpu_index());
0045 }
0046 
0047 int __init rtlx_module_init(void)
0048 {
0049     struct device *dev;
0050     int i, err;
0051 
0052     if (!cpu_has_mipsmt) {
0053         pr_warn("VPE loader: not a MIPS MT capable processor\n");
0054         return -ENODEV;
0055     }
0056 
0057     if (num_possible_cpus() - aprp_cpu_index() < 1) {
0058         pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"
0059             "Pass maxcpus=<n> argument as kernel argument\n");
0060 
0061         return -ENODEV;
0062     }
0063 
0064     major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops);
0065     if (major < 0) {
0066         pr_err("rtlx_module_init: unable to register device\n");
0067         return major;
0068     }
0069 
0070     /* initialise the wait queues */
0071     for (i = 0; i < RTLX_CHANNELS; i++) {
0072         init_waitqueue_head(&channel_wqs[i].rt_queue);
0073         init_waitqueue_head(&channel_wqs[i].lx_queue);
0074         atomic_set(&channel_wqs[i].in_open, 0);
0075         mutex_init(&channel_wqs[i].mutex);
0076 
0077         dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
0078                     "%s%d", RTLX_MODULE_NAME, i);
0079         if (IS_ERR(dev)) {
0080             while (i--)
0081                 device_destroy(mt_class, MKDEV(major, i));
0082 
0083             err = PTR_ERR(dev);
0084             goto out_chrdev;
0085         }
0086     }
0087 
0088     /* set up notifiers */
0089     rtlx_notify.start = rtlx_starting;
0090     rtlx_notify.stop = rtlx_stopping;
0091     vpe_notify(aprp_cpu_index(), &rtlx_notify);
0092 
0093     if (cpu_has_vint) {
0094         aprp_hook = rtlx_interrupt;
0095     } else {
0096         pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
0097         err = -ENODEV;
0098         goto out_class;
0099     }
0100 
0101     return 0;
0102 
0103 out_class:
0104     for (i = 0; i < RTLX_CHANNELS; i++)
0105         device_destroy(mt_class, MKDEV(major, i));
0106 out_chrdev:
0107     unregister_chrdev(major, RTLX_MODULE_NAME);
0108 
0109     return err;
0110 }
0111 
0112 void __exit rtlx_module_exit(void)
0113 {
0114     int i;
0115 
0116     for (i = 0; i < RTLX_CHANNELS; i++)
0117         device_destroy(mt_class, MKDEV(major, i));
0118 
0119     unregister_chrdev(major, RTLX_MODULE_NAME);
0120 
0121     aprp_hook = NULL;
0122 }