^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2013 Imagination Technologies Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/mips_mt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/vpe.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/rtlx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static int major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static void rtlx_dispatch(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (read_c0_cause() & read_c0_status() & C_SW0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Interrupt handler may be called before rtlx_init has otherwise had
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * a chance to run.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int vpeflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) vpeflags = dvpe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) irq_enable_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) evpe(vpeflags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) for (i = 0; i < RTLX_CHANNELS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) wake_up(&channel_wqs[i].lx_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) wake_up(&channel_wqs[i].rt_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) void _interrupt_sp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) dvpe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) settc(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) write_vpe_c0_cause(read_vpe_c0_cause() | C_SW0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) evpe(EVPE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int __init rtlx_module_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (!cpu_has_mipsmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) pr_warn("VPE loader: not a MIPS MT capable processor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (aprp_cpu_index() == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) "Pass maxtcs=<n> argument as kernel argument\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (major < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) pr_err("rtlx_module_init: unable to register device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* initialise the wait queues */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) for (i = 0; i < RTLX_CHANNELS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) init_waitqueue_head(&channel_wqs[i].rt_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) init_waitqueue_head(&channel_wqs[i].lx_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) atomic_set(&channel_wqs[i].in_open, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) mutex_init(&channel_wqs[i].mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) "%s%d", RTLX_MODULE_NAME, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (IS_ERR(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) while (i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) device_destroy(mt_class, MKDEV(major, i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) err = PTR_ERR(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) goto out_chrdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* set up notifiers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) rtlx_notify.start = rtlx_starting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) rtlx_notify.stop = rtlx_stopping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) vpe_notify(aprp_cpu_index(), &rtlx_notify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (cpu_has_vint) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) aprp_hook = rtlx_dispatch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) goto out_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) err = request_irq(rtlx_irq_num, rtlx_interrupt, 0, "RTLX", rtlx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) goto out_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) out_class:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) for (i = 0; i < RTLX_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) device_destroy(mt_class, MKDEV(major, i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) out_chrdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unregister_chrdev(major, RTLX_MODULE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) void __exit rtlx_module_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) for (i = 0; i < RTLX_CHANNELS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) device_destroy(mt_class, MKDEV(major, i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) unregister_chrdev(major, RTLX_MODULE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) aprp_hook = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }