Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: APRP: Add VPE loader support for CMP platforms.

This patch adds VPE loader support for platforms having a CMP.

Signed-off-by: Deng-Cheng Zhu <dengcheng.zhu@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
Reviewed-by: Qais Yousef <Qais.Yousef@imgtec.com>
Signed-off-by: John Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/6092/

authored by

Deng-Cheng Zhu and committed by
Ralf Baechle
17a1d523 1a2a6d7e

+186
+5
arch/mips/Kconfig
··· 1907 1907 Includes a loader for loading an elf relocatable object 1908 1908 onto another VPE and running it. 1909 1909 1910 + config MIPS_VPE_LOADER_CMP 1911 + bool 1912 + default "y" 1913 + depends on MIPS_VPE_LOADER && MIPS_CMP 1914 + 1910 1915 config MIPS_VPE_LOADER_MT 1911 1916 bool 1912 1917 default "y"
+1
arch/mips/kernel/Makefile
··· 56 56 obj-$(CONFIG_CPU_MIPSR2) += spram.o 57 57 58 58 obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o 59 + obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o 59 60 obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o 60 61 obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o 61 62
+180
arch/mips/kernel/vpe-cmp.c
··· 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 + 17 + static int major; 18 + 19 + void cleanup_tc(struct tc *tc) 20 + { 21 + 22 + } 23 + 24 + static 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 + } 38 + static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); 39 + 40 + static 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 + 48 + static 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 + } 67 + static DEVICE_ATTR_RW(ntcs); 68 + 69 + static struct attribute *vpe_attrs[] = { 70 + &dev_attr_kill.attr, 71 + &dev_attr_ntcs.attr, 72 + NULL, 73 + }; 74 + ATTRIBUTE_GROUPS(vpe); 75 + 76 + static void vpe_device_release(struct device *cd) 77 + { 78 + kfree(cd); 79 + } 80 + 81 + static struct class vpe_class = { 82 + .name = "vpe", 83 + .owner = THIS_MODULE, 84 + .dev_release = vpe_device_release, 85 + .dev_groups = vpe_groups, 86 + }; 87 + 88 + static struct device vpe_device; 89 + 90 + int __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 + 156 + out_dev: 157 + device_del(&vpe_device); 158 + 159 + out_class: 160 + class_unregister(&vpe_class); 161 + 162 + out_chrdev: 163 + unregister_chrdev(major, VPE_MODULE_NAME); 164 + 165 + return err; 166 + } 167 + 168 + void __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 + }