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) 2004, 2005 MIPS Technologies, Inc. All rights reserved. 7 * Copyright (C) 2013 Imagination Technologies Ltd. 8 */ 9#include <linux/kernel.h> 10#include <linux/device.h> 11#include <linux/fs.h> 12#include <linux/slab.h> 13#include <linux/export.h> 14 15#include <asm/vpe.h> 16 17static int major; 18 19void cleanup_tc(struct tc *tc) 20{ 21 22} 23 24static ssize_t store_kill(struct device *dev, struct device_attribute *attr, 25 const char *buf, size_t len) 26{ 27 struct vpe *vpe = get_vpe(aprp_cpu_index()); 28 struct vpe_notifications *notifier; 29 30 list_for_each_entry(notifier, &vpe->notify, list) 31 notifier->stop(aprp_cpu_index()); 32 33 release_progmem(vpe->load_addr); 34 vpe->state = VPE_STATE_UNUSED; 35 36 return len; 37} 38static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); 39 40static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, 41 char *buf) 42{ 43 struct vpe *vpe = get_vpe(aprp_cpu_index()); 44 45 return sprintf(buf, "%d\n", vpe->ntcs); 46} 47 48static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, 49 const char *buf, size_t len) 50{ 51 struct vpe *vpe = get_vpe(aprp_cpu_index()); 52 unsigned long new; 53 int ret; 54 55 ret = kstrtoul(buf, 0, &new); 56 if (ret < 0) 57 return ret; 58 59 /* APRP can only reserve one TC in a VPE and no more. */ 60 if (new != 1) 61 return -EINVAL; 62 63 vpe->ntcs = new; 64 65 return len; 66} 67static DEVICE_ATTR_RW(ntcs); 68 69static struct attribute *vpe_attrs[] = { 70 &dev_attr_kill.attr, 71 &dev_attr_ntcs.attr, 72 NULL, 73}; 74ATTRIBUTE_GROUPS(vpe); 75 76static void vpe_device_release(struct device *cd) 77{ 78 kfree(cd); 79} 80 81static struct class vpe_class = { 82 .name = "vpe", 83 .owner = THIS_MODULE, 84 .dev_release = vpe_device_release, 85 .dev_groups = vpe_groups, 86}; 87 88static struct device vpe_device; 89 90int __init vpe_module_init(void) 91{ 92 struct vpe *v = NULL; 93 struct tc *t; 94 int err; 95 96 if (!cpu_has_mipsmt) { 97 pr_warn("VPE loader: not a MIPS MT capable processor\n"); 98 return -ENODEV; 99 } 100 101 if (num_possible_cpus() - aprp_cpu_index() < 1) { 102 pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n" 103 "Pass maxcpus=<n> argument as kernel argument\n"); 104 return -ENODEV; 105 } 106 107 major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops); 108 if (major < 0) { 109 pr_warn("VPE loader: unable to register character device\n"); 110 return major; 111 } 112 113 err = class_register(&vpe_class); 114 if (err) { 115 pr_err("vpe_class registration failed\n"); 116 goto out_chrdev; 117 } 118 119 device_initialize(&vpe_device); 120 vpe_device.class = &vpe_class, 121 vpe_device.parent = NULL, 122 dev_set_name(&vpe_device, "vpe_sp"); 123 vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR); 124 err = device_add(&vpe_device); 125 if (err) { 126 pr_err("Adding vpe_device failed\n"); 127 goto out_class; 128 } 129 130 t = alloc_tc(aprp_cpu_index()); 131 if (!t) { 132 pr_warn("VPE: unable to allocate TC\n"); 133 err = -ENOMEM; 134 goto out_dev; 135 } 136 137 /* VPE */ 138 v = alloc_vpe(aprp_cpu_index()); 139 if (v == NULL) { 140 pr_warn("VPE: unable to allocate VPE\n"); 141 kfree(t); 142 err = -ENOMEM; 143 goto out_dev; 144 } 145 146 v->ntcs = 1; 147 148 /* add the tc to the list of this vpe's tc's. */ 149 list_add(&t->tc, &v->tc); 150 151 /* TC */ 152 t->pvpe = v; /* set the parent vpe */ 153 154 return 0; 155 156out_dev: 157 device_del(&vpe_device); 158 159out_class: 160 class_unregister(&vpe_class); 161 162out_chrdev: 163 unregister_chrdev(major, VPE_MODULE_NAME); 164 165 return err; 166} 167 168void __exit vpe_module_exit(void) 169{ 170 struct vpe *v, *n; 171 172 device_del(&vpe_device); 173 class_unregister(&vpe_class); 174 unregister_chrdev(major, VPE_MODULE_NAME); 175 176 /* No locking needed here */ 177 list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) 178 if (v->state != VPE_STATE_UNUSED) 179 release_vpe(v); 180} 181