rtlx-cmp.c (2693B)
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. 7 * Copyright (C) 2013 Imagination Technologies Ltd. 8 */ 9#include <linux/device.h> 10#include <linux/fs.h> 11#include <linux/err.h> 12#include <linux/wait.h> 13#include <linux/sched.h> 14#include <linux/smp.h> 15 16#include <asm/mips_mt.h> 17#include <asm/vpe.h> 18#include <asm/rtlx.h> 19 20static int major; 21 22static void rtlx_interrupt(void) 23{ 24 int i; 25 struct rtlx_info *info; 26 struct rtlx_info **p = vpe_get_shared(aprp_cpu_index()); 27 28 if (p == NULL || *p == NULL) 29 return; 30 31 info = *p; 32 33 if (info->ap_int_pending == 1 && smp_processor_id() == 0) { 34 for (i = 0; i < RTLX_CHANNELS; i++) { 35 wake_up(&channel_wqs[i].lx_queue); 36 wake_up(&channel_wqs[i].rt_queue); 37 } 38 info->ap_int_pending = 0; 39 } 40} 41 42void _interrupt_sp(void) 43{ 44 smp_send_reschedule(aprp_cpu_index()); 45} 46 47int __init rtlx_module_init(void) 48{ 49 struct device *dev; 50 int i, err; 51 52 if (!cpu_has_mipsmt) { 53 pr_warn("VPE loader: not a MIPS MT capable processor\n"); 54 return -ENODEV; 55 } 56 57 if (num_possible_cpus() - aprp_cpu_index() < 1) { 58 pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n" 59 "Pass maxcpus=<n> argument as kernel argument\n"); 60 61 return -ENODEV; 62 } 63 64 major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops); 65 if (major < 0) { 66 pr_err("rtlx_module_init: unable to register device\n"); 67 return major; 68 } 69 70 /* initialise the wait queues */ 71 for (i = 0; i < RTLX_CHANNELS; i++) { 72 init_waitqueue_head(&channel_wqs[i].rt_queue); 73 init_waitqueue_head(&channel_wqs[i].lx_queue); 74 atomic_set(&channel_wqs[i].in_open, 0); 75 mutex_init(&channel_wqs[i].mutex); 76 77 dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, 78 "%s%d", RTLX_MODULE_NAME, i); 79 if (IS_ERR(dev)) { 80 while (i--) 81 device_destroy(mt_class, MKDEV(major, i)); 82 83 err = PTR_ERR(dev); 84 goto out_chrdev; 85 } 86 } 87 88 /* set up notifiers */ 89 rtlx_notify.start = rtlx_starting; 90 rtlx_notify.stop = rtlx_stopping; 91 vpe_notify(aprp_cpu_index(), &rtlx_notify); 92 93 if (cpu_has_vint) { 94 aprp_hook = rtlx_interrupt; 95 } else { 96 pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); 97 err = -ENODEV; 98 goto out_class; 99 } 100 101 return 0; 102 103out_class: 104 for (i = 0; i < RTLX_CHANNELS; i++) 105 device_destroy(mt_class, MKDEV(major, i)); 106out_chrdev: 107 unregister_chrdev(major, RTLX_MODULE_NAME); 108 109 return err; 110} 111 112void __exit rtlx_module_exit(void) 113{ 114 int i; 115 116 for (i = 0; i < RTLX_CHANNELS; i++) 117 device_destroy(mt_class, MKDEV(major, i)); 118 119 unregister_chrdev(major, RTLX_MODULE_NAME); 120 121 aprp_hook = NULL; 122}