#include <asm/system.h>
#include <asm/vpe.h>
#include <asm/kspd.h>
-#include <asm/mips_mt.h>
typedef void *vpe_handle;
static const int minor = 1; /* fixed for now */
#ifdef CONFIG_MIPS_APSP_KSPD
- static struct kspd_notifications kspd_events;
-static int kspd_events_reqd = 0;
+static struct kspd_notifications kspd_events;
+static int kspd_events_reqd;
#endif
/* grab the likely amount of memory we will need. */
};
struct {
- /* Virtual processing elements */
- struct list_head vpe_list;
-
- /* Thread contexts */
- struct list_head tc_list;
+ spinlock_t vpe_list_lock;
+ struct list_head vpe_list; /* Virtual processing elements */
+ spinlock_t tc_list_lock;
+ struct list_head tc_list; /* Thread contexts */
} vpecontrol = {
- .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
- .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
+ .vpe_list_lock = SPIN_LOCK_UNLOCKED,
+ .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
+ .tc_list_lock = SPIN_LOCK_UNLOCKED,
+ .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
};
static void release_progmem(void *ptr);
-extern void save_gp_address(unsigned int secbase, unsigned int rel);
/* get the vpe associated with this minor */
-struct vpe *get_vpe(int minor)
+static struct vpe *get_vpe(int minor)
{
- struct vpe *v;
+ struct vpe *res, *v;
if (!cpu_has_mipsmt)
return NULL;
+ res = NULL;
+ spin_lock(&vpecontrol.vpe_list_lock);
list_for_each_entry(v, &vpecontrol.vpe_list, list) {
- if (v->minor == minor)
- return v;
+ if (v->minor == minor) {
+ res = v;
+ break;
+ }
}
+ spin_unlock(&vpecontrol.vpe_list_lock);
- return NULL;
+ return res;
}
/* get the vpe associated with this minor */
-struct tc *get_tc(int index)
-{
- struct tc *t;
-
- list_for_each_entry(t, &vpecontrol.tc_list, list) {
- if (t->index == index)
- return t;
- }
-
- return NULL;
-}
-
-struct tc *get_tc_unused(void)
+static struct tc *get_tc(int index)
{
- struct tc *t;
+ struct tc *res, *t;
+ res = NULL;
+ spin_lock(&vpecontrol.tc_list_lock);
list_for_each_entry(t, &vpecontrol.tc_list, list) {
- if (t->state == TC_STATE_UNUSED)
- return t;
+ if (t->index == index) {
+ res = t;
+ break;
+ }
}
+ spin_unlock(&vpecontrol.tc_list_lock);
return NULL;
}
/* allocate a vpe and associate it with this minor (or index) */
-struct vpe *alloc_vpe(int minor)
+static struct vpe *alloc_vpe(int minor)
{
struct vpe *v;
- if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
+ if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL)
return NULL;
- }
INIT_LIST_HEAD(&v->tc);
+ spin_lock(&vpecontrol.vpe_list_lock);
list_add_tail(&v->list, &vpecontrol.vpe_list);
+ spin_unlock(&vpecontrol.vpe_list_lock);
INIT_LIST_HEAD(&v->notify);
v->minor = minor;
+
return v;
}
/* allocate a tc. At startup only tc0 is running, all other can be halted. */
-struct tc *alloc_tc(int index)
+static struct tc *alloc_tc(int index)
{
struct tc *tc;
INIT_LIST_HEAD(&tc->tc);
tc->index = index;
+
+ spin_lock(&vpecontrol.tc_list_lock);
list_add_tail(&tc->list, &vpecontrol.tc_list);
+ spin_unlock(&vpecontrol.tc_list_lock);
out:
return tc;
}
/* clean up and free everything */
-void release_vpe(struct vpe *v)
+static void release_vpe(struct vpe *v)
{
list_del(&v->list);
if (v->load_addr)
kfree(v);
}
-void dump_mtregs(void)
+static void __maybe_unused dump_mtregs(void)
{
unsigned long val;
/* Find some VPE program space */
static void *alloc_progmem(unsigned long len)
{
+ void *addr;
+
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
- /* this means you must tell linux to use less memory than you physically have */
- return pfn_to_kaddr(max_pfn);
+ /*
+ * This means you must tell Linux to use less memory than you
+ * physically have, for example by passing a mem= boot argument.
+ */
+ addr = pfn_to_kaddr(max_low_pfn);
+ memset(addr, 0, len);
#else
- // simple grab some mem for now
- return kmalloc(len, GFP_KERNEL);
+ /* simple grab some mem for now */
+ addr = kzalloc(len, GFP_KERNEL);
#endif
+
+ return addr;
}
static void release_progmem(void *ptr)
|| (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL)
continue;
- s->sh_entsize = get_offset(&mod->core_size, s);
+ s->sh_entsize =
+ get_offset((unsigned long *)&mod->core_size, s);
}
if (m == 0)
{
unsigned long insnlo = *location;
Elf32_Addr val, vallo;
+ struct mips_hi16 *l, *next;
/* Sign extend the addend we extract from the lo insn. */
vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
if (mips_hi16_list != NULL) {
- struct mips_hi16 *l;
l = mips_hi16_list;
while (l != NULL) {
- struct mips_hi16 *next;
unsigned long insn;
/*
*/
if (v != l->value) {
printk(KERN_DEBUG "VPE loader: "
- "apply_r_mips_lo16/hi16: "
+ "apply_r_mips_lo16/hi16: \t"
"inconsistent value information\n");
- return -ENOEXEC;
+ goto out_free;
}
/*
*location = insnlo;
return 0;
+
+out_free:
+ while (l != NULL) {
+ next = l->next;
+ kfree(l);
+ l = next;
+ }
+ mips_hi16_list = NULL;
+
+ return -ENOEXEC;
}
static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
[R_MIPS_PC16] = "MIPS_PC16"
};
-int apply_relocations(Elf32_Shdr *sechdrs,
+static int apply_relocations(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
return 0;
}
-void save_gp_address(unsigned int secbase, unsigned int rel)
+static inline void save_gp_address(unsigned int secbase, unsigned int rel)
{
gp_addr = secbase + rel;
gp_offs = gp_addr - (secbase & 0xffff0000);
break;
case SHN_MIPS_SCOMMON:
- printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON"
+ printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
"symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
sym[i].st_shndx);
// .sbss section
/* take system out of configuration state */
clear_c0_mvpcontrol(MVPCONTROL_VPC);
+ /*
+ * SMTC/SMVP kernels manage VPE enable independently,
+ * but uniprocessor kernels need to turn it on, even
+ * if that wasn't the pre-dvpe() state.
+ */
#ifdef CONFIG_SMP
- evpe(EVPE_ENABLE);
-#else
evpe(vpeflags);
+#else
+ evpe(EVPE_ENABLE);
#endif
emt(dmt_flag);
local_irq_restore(flags);
/* Sanity checks against insmoding binaries or wrong arch,
weird elf version */
- if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
+ if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|| (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
|| !elf_check_arch(hdr)
|| hdr->e_shentsize != sizeof(*sechdrs)) {
}
v->load_addr = alloc_progmem(mod.core_size);
- memset(v->load_addr, 0, mod.core_size);
+ if (!v->load_addr)
+ return -ENOMEM;
- printk("VPE loader: loading to %p\n", v->load_addr);
+ pr_info("VPE loader: loading to %p\n", v->load_addr);
if (relocate) {
for (i = 0; i < hdr->e_shnum; i++) {
struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff);
for (i = 0; i < hdr->e_phnum; i++) {
- if (phdr->p_type != PT_LOAD)
- continue;
-
- memcpy((void *)phdr->p_paddr, (char *)hdr + phdr->p_offset, phdr->p_filesz);
- memset((void *)phdr->p_paddr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
- phdr++;
+ if (phdr->p_type == PT_LOAD) {
+ memcpy((void *)phdr->p_paddr,
+ (char *)hdr + phdr->p_offset,
+ phdr->p_filesz);
+ memset((void *)phdr->p_paddr + phdr->p_filesz,
+ 0, phdr->p_memsz - phdr->p_filesz);
+ }
+ phdr++;
}
for (i = 0; i < hdr->e_shnum; i++) {
if (minor != iminor(inode)) {
/* assume only 1 device at the moment. */
- printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
+ pr_warning("VPE loader: only vpe1 is supported\n");
+
return -ENODEV;
}
if ((v = get_vpe(tclimit)) == NULL) {
- printk(KERN_WARNING "VPE loader: unable to get vpe\n");
+ pr_warning("VPE loader: unable to get vpe\n");
+
return -ENODEV;
}
v->load_addr = NULL;
v->len = 0;
- v->uid = filp->f_uid;
- v->gid = filp->f_gid;
+ v->uid = filp->f_cred->fsuid;
+ v->gid = filp->f_cred->fsgid;
#ifdef CONFIG_MIPS_APSP_KSPD
/* get kspd to tell us when a syscall_exit happens */
return -ENODEV;
hdr = (Elf_Ehdr *) v->pbuffer;
- if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {
+ if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) {
if (vpe_elfload(v) >= 0) {
vpe_run(v);
} else {
/* It's good to be able to run the SP and if it chokes have a look at
the /dev/rt?. But if we reset the pointer to the shared struct we
- loose what has happened. So perhaps if garbage is sent to the vpe
+ lose what has happened. So perhaps if garbage is sent to the vpe
device, use it as a trigger for the reset. Hopefully a nice
executable will be along shortly. */
if (ret < 0)
return len;
out_einval:
- return -EINVAL;;
+ return -EINVAL;
}
static struct device_attribute vpe_class_attributes[] = {
device_initialize(&vpe_device);
vpe_device.class = &vpe_class,
vpe_device.parent = NULL,
- strlcpy(vpe_device.bus_id, "vpe1", BUS_ID_SIZE);
+ dev_set_name(&vpe_device, "vpe1");
vpe_device.devt = MKDEV(major, minor);
err = device_add(&vpe_device);
if (err) {
{
struct vpe *v, *n;
+ device_del(&vpe_device);
+ unregister_chrdev(major, module_name);
+
+ /* No locking needed here */
list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
- if (v->state != VPE_STATE_UNUSED) {
+ if (v->state != VPE_STATE_UNUSED)
release_vpe(v);
- }
}
-
- device_del(&vpe_device);
- unregister_chrdev(major, module_name);
}
module_init(vpe_module_init);