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) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
0007  * Copyright (C) 2013 Imagination Technologies Ltd.
0008  */
0009 #include <linux/kernel.h>
0010 #include <linux/device.h>
0011 #include <linux/fs.h>
0012 #include <linux/slab.h>
0013 #include <linux/export.h>
0014 
0015 #include <asm/vpe.h>
0016 
0017 static int major;
0018 
0019 void cleanup_tc(struct tc *tc)
0020 {
0021 
0022 }
0023 
0024 static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
0025               const char *buf, size_t len)
0026 {
0027     struct vpe *vpe = get_vpe(aprp_cpu_index());
0028     struct vpe_notifications *notifier;
0029 
0030     list_for_each_entry(notifier, &vpe->notify, list)
0031         notifier->stop(aprp_cpu_index());
0032 
0033     release_progmem(vpe->load_addr);
0034     vpe->state = VPE_STATE_UNUSED;
0035 
0036     return len;
0037 }
0038 static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
0039 
0040 static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
0041              char *buf)
0042 {
0043     struct vpe *vpe = get_vpe(aprp_cpu_index());
0044 
0045     return sprintf(buf, "%d\n", vpe->ntcs);
0046 }
0047 
0048 static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
0049               const char *buf, size_t len)
0050 {
0051     struct vpe *vpe = get_vpe(aprp_cpu_index());
0052     unsigned long new;
0053     int ret;
0054 
0055     ret = kstrtoul(buf, 0, &new);
0056     if (ret < 0)
0057         return ret;
0058 
0059     /* APRP can only reserve one TC in a VPE and no more. */
0060     if (new != 1)
0061         return -EINVAL;
0062 
0063     vpe->ntcs = new;
0064 
0065     return len;
0066 }
0067 static DEVICE_ATTR_RW(ntcs);
0068 
0069 static struct attribute *vpe_attrs[] = {
0070     &dev_attr_kill.attr,
0071     &dev_attr_ntcs.attr,
0072     NULL,
0073 };
0074 ATTRIBUTE_GROUPS(vpe);
0075 
0076 static void vpe_device_release(struct device *cd)
0077 {
0078     kfree(cd);
0079 }
0080 
0081 static struct class vpe_class = {
0082     .name = "vpe",
0083     .owner = THIS_MODULE,
0084     .dev_release = vpe_device_release,
0085     .dev_groups = vpe_groups,
0086 };
0087 
0088 static struct device vpe_device;
0089 
0090 int __init vpe_module_init(void)
0091 {
0092     struct vpe *v = NULL;
0093     struct tc *t;
0094     int err;
0095 
0096     if (!cpu_has_mipsmt) {
0097         pr_warn("VPE loader: not a MIPS MT capable processor\n");
0098         return -ENODEV;
0099     }
0100 
0101     if (num_possible_cpus() - aprp_cpu_index() < 1) {
0102         pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n"
0103             "Pass maxcpus=<n> argument as kernel argument\n");
0104         return -ENODEV;
0105     }
0106 
0107     major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops);
0108     if (major < 0) {
0109         pr_warn("VPE loader: unable to register character device\n");
0110         return major;
0111     }
0112 
0113     err = class_register(&vpe_class);
0114     if (err) {
0115         pr_err("vpe_class registration failed\n");
0116         goto out_chrdev;
0117     }
0118 
0119     device_initialize(&vpe_device);
0120     vpe_device.class    = &vpe_class;
0121     vpe_device.parent   = NULL;
0122     dev_set_name(&vpe_device, "vpe_sp");
0123     vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR);
0124     err = device_add(&vpe_device);
0125     if (err) {
0126         pr_err("Adding vpe_device failed\n");
0127         goto out_class;
0128     }
0129 
0130     t = alloc_tc(aprp_cpu_index());
0131     if (!t) {
0132         pr_warn("VPE: unable to allocate TC\n");
0133         err = -ENOMEM;
0134         goto out_dev;
0135     }
0136 
0137     /* VPE */
0138     v = alloc_vpe(aprp_cpu_index());
0139     if (v == NULL) {
0140         pr_warn("VPE: unable to allocate VPE\n");
0141         kfree(t);
0142         err = -ENOMEM;
0143         goto out_dev;
0144     }
0145 
0146     v->ntcs = 1;
0147 
0148     /* add the tc to the list of this vpe's tc's. */
0149     list_add(&t->tc, &v->tc);
0150 
0151     /* TC */
0152     t->pvpe = v;    /* set the parent vpe */
0153 
0154     return 0;
0155 
0156 out_dev:
0157     device_del(&vpe_device);
0158 
0159 out_class:
0160     class_unregister(&vpe_class);
0161 
0162 out_chrdev:
0163     unregister_chrdev(major, VPE_MODULE_NAME);
0164 
0165     return err;
0166 }
0167 
0168 void __exit vpe_module_exit(void)
0169 {
0170     struct vpe *v, *n;
0171 
0172     device_del(&vpe_device);
0173     class_unregister(&vpe_class);
0174     unregister_chrdev(major, VPE_MODULE_NAME);
0175 
0176     /* No locking needed here */
0177     list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list)
0178         if (v->state != VPE_STATE_UNUSED)
0179             release_vpe(v);
0180 }