big commit

This commit is contained in:
Taku Shimosawa
2011-11-28 13:00:13 +09:00
parent ea0e1327c8
commit 480e1b12ef
21 changed files with 1866 additions and 89 deletions

View File

@ -6,7 +6,7 @@ endif
obj-m += mcctrl.o
mcctrl-objs := driver.o control.o
mcctrl-objs := driver.o control.o ikc.o
AAL_BASE=$(src)/../../../aal
EXTRA_CFLAGS = -I$(AAL_BASE)/host/include -I$(AAL_BASE)/ikc/include -I$(src)/../include

View File

@ -1,51 +1,279 @@
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include "mcctrl.h"
static struct aal_ikc_listen_param __listen_param = {
.port = 501,
.handler = test_handler,
.pkt_size = sizeof(struct ikc_test_packet),
.queue_size = 4096,
.magic = 0x29,
};
static DECLARE_WAIT_QUEUE_HEAD(wq_prepare);
extern struct mcctrl_channel *channels;
int mcctrl_ikc_set_recv_cpu(int cpu);
static long mcexec_prepare_image(struct mcctrl_priv *data,
static long mcexec_prepare_image(aal_os_t os,
struct program_load_desc * __user udesc)
{
struct program_load_desc desc;
struct program_load_desc desc, *pdesc;
struct ikc_scd_packet isp;
if (!copy_from_user(&desc, udesc,
if (copy_from_user(&desc, udesc,
sizeof(struct program_load_desc))) {
return -EFAULT;
}
if (desc.num_sections <= 0 || desc.num_sections > 16) {
printk("# of sections: %d\n", desc.num_sections);
return -EINVAL;
}
data->desc = kmalloc(sizeof(struct program_load_desc) +
sizeof(struct program_image_section)
* desc.num_sections, GFP_KERNEL);
memcpy(data->desc, &desc, sizeof(struct program_load_desc));
if (!copy_from_user(data->desc->sections, udesc->sections,
sizeof(struct program_image_section)
* desc.num_sections)) {
kfree(data->desc);
pdesc = kmalloc(sizeof(struct program_load_desc) +
sizeof(struct program_image_section)
* desc.num_sections, GFP_KERNEL);
memcpy(pdesc, &desc, sizeof(struct program_load_desc));
if (copy_from_user(pdesc->sections, udesc->sections,
sizeof(struct program_image_section)
* desc.num_sections)) {
kfree(pdesc);
return -EFAULT;
}
pdesc->pid = task_tgid_vnr(current);
isp.msg = SCD_MSG_PREPARE_PROCESS;
isp.ref = pdesc->cpu;
isp.arg = virt_to_phys(pdesc);
printk("# of sections: %d\n", pdesc->num_sections);
printk("%p (%lx)\n", pdesc, isp.arg);
pdesc->status = 0;
mcctrl_ikc_send(pdesc->cpu, &isp);
wait_event_interruptible(wq_prepare, pdesc->status);
copy_to_user(udesc, pdesc, sizeof(struct program_load_desc) +
sizeof(struct program_image_section) * desc.num_sections);
kfree(pdesc);
return 0;
}
int mcexec_load_image(aal_os_t os, struct program_transfer *__user upt)
{
struct program_transfer pt;
unsigned long dma_status = 0;
aal_dma_channel_t channel;
struct aal_dma_request request;
void *p;
channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0);
if (!channel) {
return -EINVAL;
}
if (copy_from_user(&pt, upt, sizeof(pt))) {
return -EFAULT;
}
p = (void *)__get_free_page(GFP_KERNEL);
if (copy_from_user(p, pt.src, PAGE_SIZE)) {
return -EFAULT;
}
memset(&request, 0, sizeof(request));
request.src_os = NULL;
request.src_phys = virt_to_phys(p);
request.dest_os = os;
request.dest_phys = pt.dest;
request.size = PAGE_SIZE;
request.notify = (void *)virt_to_phys(&dma_status);
request.priv = (void *)1;
aal_dma_request(channel, &request);
while (!dma_status) {
mb();
udelay(1);
}
free_page((unsigned long)p);
return 0;
}
static long mcexec_start_image(aal_os_t os,
struct program_load_desc * __user udesc)
{
struct program_load_desc desc;
struct ikc_scd_packet isp;
if (copy_from_user(&desc, udesc,
sizeof(struct program_load_desc))) {
return -EFAULT;
}
mcctrl_ikc_set_recv_cpu(desc.cpu);
isp.msg = SCD_MSG_SCHEDULE_PROCESS;
isp.ref = desc.cpu;
isp.arg = desc.rprocess;
mcctrl_ikc_send(desc.cpu, &isp);
return 0;
}
int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg)
{
c->req = 1;
wake_up(&c->wq_syscall);
return 0;
}
int mcexec_wait_syscall(aal_os_t os, struct syscall_wait_desc *__user req)
{
struct syscall_wait_desc swd;
struct mcctrl_channel *c;
if (copy_from_user(&swd, req, sizeof(swd.cpu))) {
return -EFAULT;
}
c = channels + swd.cpu;
wait_event_interruptible(c->wq_syscall, c->req);
c->req = 0;
if (copy_to_user(&req->sr, c->param.request_va,
sizeof(struct syscall_request))) {
return -EFAULT;
}
return 0;
}
long __mcctrl_control(struct mcctrl_priv *data, unsigned int req,
unsigned long arg)
long mcexec_pin_region(aal_os_t os, unsigned long *__user uaddress)
{
int pin_shift = 16;
unsigned long a;
a = __get_free_pages(GFP_KERNEL, pin_shift - PAGE_SHIFT);
if (!a) {
return -ENOMEM;
}
a = virt_to_phys((void *)a);
if (copy_to_user(uaddress, &a, sizeof(unsigned long))) {
return -EFAULT;
}
return 0;
}
long mcexec_load_syscall(aal_os_t os, struct syscall_load_desc *__user arg)
{
struct syscall_load_desc desc;
aal_dma_channel_t channel;
struct aal_dma_request request;
channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0);
if (!channel) {
return -EINVAL;
}
if (copy_from_user(&desc, arg, sizeof(struct syscall_load_desc))) {
return -EFAULT;
}
memset(&request, 0, sizeof(request));
request.src_os = os;
request.src_phys = desc.src;
request.dest_os = NULL;
request.dest_phys = desc.dest;
request.size = desc.size;
request.notify = (void *)(desc.dest + desc.size);
request.priv = (void *)1;
aal_dma_request(channel, &request);
return 0;
}
long mcexec_ret_syscall(aal_os_t os, struct syscall_ret_desc *__user arg)
{
struct syscall_ret_desc ret;
aal_dma_channel_t channel;
struct aal_dma_request request;
struct mcctrl_channel *mc;
channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0);
if (!channel) {
return -EINVAL;
}
if (copy_from_user(&ret, arg, sizeof(struct syscall_ret_desc))) {
return -EFAULT;
}
mc = channels + ret.cpu;
if (!mc) {
return -EINVAL;
}
mc->param.response_va->ret = ret.ret;
if (ret.size > 0) {
memset(&request, 0, sizeof(request));
request.src_os = NULL;
request.src_phys = ret.src;
request.dest_os = os;
request.dest_phys = ret.dest;
request.size = ret.size;
request.notify = (void *)mc->param.response_pa;
request.priv = (void *)1;
aal_dma_request(channel, &request);
} else {
mc->param.response_va->status = 1;
}
return 0;
}
long __mcctrl_control(aal_os_t os, unsigned int req, unsigned long arg)
{
switch (req) {
case MCEXEC_UP_PREPARE_IMAGE:
return mcexec_prepare_image((struct mcctrl_priv *)data,
return mcexec_prepare_image(os,
(struct program_load_desc *)arg);
case MCEXEC_UP_LOAD_IMAGE:
return mcexec_load_image(os, (struct program_transfer *)arg);
case MCEXEC_UP_START_IMAGE:
return mcexec_start_image(os, (struct program_load_desc *)arg);
case MCEXEC_UP_WAIT_SYSCALL:
return mcexec_wait_syscall(os, (struct syscall_wait_desc *)arg);
case MCEXEC_UP_RET_SYSCALL:
return mcexec_ret_syscall(os, (struct syscall_ret_desc *)arg);
case MCEXEC_UP_LOAD_SYSCALL:
return mcexec_load_syscall(os, (struct syscall_load_desc *)arg);
case MCEXEC_UP_PREPARE_DMA:
return mcexec_pin_region(os, (unsigned long *)arg);
}
return -EINVAL;
}
void mcexec_prepare_ack(unsigned long arg)
{
struct program_load_desc *desc = phys_to_virt(arg);
desc->status = 1;
wake_up_all(&wq_prepare);
}

View File

@ -9,63 +9,51 @@
#include <linux/slab.h>
#include "mcctrl.h"
extern long __mcctrl_control(struct mcctrl_priv *, unsigned int, unsigned long);
extern long __mcctrl_control(aal_os_t, unsigned int, unsigned long);
extern int prepare_ikc_channels(aal_os_t os);
static int mcctrl_open(struct inode *inode, struct file *file)
{
struct mcctrl_priv *mcc_data;
mcc_data = kzalloc(sizeof(struct mcctrl_priv), GFP_KERNEL);
if (!mcc_data) {
return -ENOMEM;
}
file->private_data = mcc_data;
return 0;
}
static int mcctrl_release(struct inode *inode, struct file *file)
{
struct mcctrl_priv *mcc_data = file->private_data;
if (mcc_data) {
if (mcc_data->desc) {
kfree(mcc_data->desc);
}
kfree(mcc_data);
}
return 0;
}
static long mcctrl_ioctl(struct file *file, unsigned int request,
static long mcctrl_ioctl(aal_os_t os, unsigned int request, void *priv,
unsigned long arg)
{
struct mcctrl_priv *mcc_data = file->private_data;
return __mcctrl_control(mcc_data, request, arg);
return __mcctrl_control(os, request, arg);
}
static struct file_operations mcctrl_ops = {
.open = mcctrl_open,
.unlocked_ioctl = mcctrl_ioctl,
.release = mcctrl_release,
static struct aal_os_user_call_handler mcctrl_uchs[] = {
{ .request = MCEXEC_UP_PREPARE_IMAGE, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_LOAD_IMAGE, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_START_IMAGE, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_WAIT_SYSCALL, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_RET_SYSCALL, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_LOAD_SYSCALL, .func = mcctrl_ioctl },
{ .request = MCEXEC_UP_PREPARE_DMA, .func = mcctrl_ioctl },
};
static struct miscdevice mcctrl_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mcctrl",
.fops = &mcctrl_ops,
static struct aal_os_user_call mcctrl_uc = {
.num_handlers = sizeof(mcctrl_uchs) / sizeof(mcctrl_uchs[0]),
.handlers = mcctrl_uchs,
};
static aal_os_t os;
static int __init mcctrl_init(void)
{
return misc_register(&mcctrl_dev);
os = aal_host_find_os(0, NULL);
if (!os) {
printk("OS #0 not found.\n");
return -ENOENT;
}
if (prepare_ikc_channels(os) != 0) {
printk("Preparing syscall channels failed.\n");
return -EINVAL;
}
return aal_os_register_user_call_handlers(os, &mcctrl_uc);
}
static void __exit mcctrl_exit(void)
{
misc_deregister(&mcctrl_dev);
aal_os_unregister_user_call_handlers(os, &mcctrl_uc);
}
MODULE_LICENSE("GPL v2");

153
linux/mod_mcctrl/ikc.c Normal file
View File

@ -0,0 +1,153 @@
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include "mcctrl.h"
#include <aal/ikc.h>
#include <ikc/master.h>
static int num_channels;
struct mcctrl_channel *channels;
void mcexec_prepare_ack(unsigned long arg);
static void mcctrl_ikc_init(aal_os_t os, int cpu, unsigned long rphys);
int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg);
static int syscall_packet_handler(struct aal_ikc_channel_desc *c,
void *__packet, void *__os)
{
struct ikc_scd_packet *pisp = __packet;
switch (pisp->msg) {
case SCD_MSG_INIT_CHANNEL:
mcctrl_ikc_init(__os, pisp->ref, pisp->arg);
break;
case SCD_MSG_PREPARE_PROCESS_ACKED:
mcexec_prepare_ack(pisp->arg);
break;
case SCD_MSG_SYSCALL_ONESIDE:
mcexec_syscall(channels + pisp->ref, pisp->arg);
break;
}
return 0;
}
int mcctrl_ikc_send(int cpu, struct ikc_scd_packet *pisp)
{
if (cpu < 0 || cpu >= num_channels || !channels[cpu].c) {
return -EINVAL;
}
return aal_ikc_send(channels[cpu].c, pisp, 0);
}
int mcctrl_ikc_set_recv_cpu(int cpu)
{
aal_ikc_channel_set_cpu(channels[cpu].c,
aal_ikc_get_processor_id());
kprintf("Setting the target to %d\n",
aal_ikc_get_processor_id());
return 0;
}
static void mcctrl_ikc_init(aal_os_t os, int cpu, unsigned long rphys)
{
struct ikc_scd_packet packet;
struct mcctrl_channel *pmc = channels + cpu;
unsigned long phys;
struct ikc_scd_init_param *rpm;
if (!pmc) {
return;
}
phys = aal_device_map_memory(aal_os_to_dev(os), rphys,
sizeof(struct ikc_scd_init_param));
rpm = ioremap_wc(phys, sizeof(struct ikc_scd_init_param));
pmc->param.request_va = (void *)__get_free_page(GFP_KERNEL);
pmc->param.request_pa = virt_to_phys(pmc->param.request_va);
pmc->param.doorbell_va = (void *)__get_free_page(GFP_KERNEL);
pmc->param.doorbell_pa = virt_to_phys(pmc->param.doorbell_va);
pmc->param.response_rpa = rpm->response_page;
pmc->param.response_pa
= aal_device_map_memory(aal_os_to_dev(os),
pmc->param.response_rpa,
PAGE_SIZE);
pmc->param.response_va = ioremap_wc(pmc->param.response_pa,
PAGE_SIZE);
rpm->request_page = pmc->param.request_pa;
rpm->doorbell_page = pmc->param.doorbell_pa;
packet.msg = SCD_MSG_INIT_CHANNEL_ACKED;
packet.ref = cpu;
packet.arg = rphys;
aal_ikc_send(pmc->c, &packet, 0);
iounmap(rpm);
aal_device_unmap_memory(aal_os_to_dev(os), phys,
sizeof(struct ikc_scd_init_param));
}
static int connect_handler(struct aal_ikc_channel_info *param)
{
struct aal_ikc_channel_desc *c;
int cpu;
c = param->channel;
cpu = c->send.queue->read_cpu;
if (cpu < 0 || cpu >= num_channels) {
kprintf("Invalid connect source processor: %d\n", cpu);
return 1;
}
param->packet_handler = syscall_packet_handler;
init_waitqueue_head(&channels[cpu].wq_syscall);
channels[cpu].c = c;
kprintf("syscall: MC CPU %d connected.\n", cpu);
return 0;
}
static struct aal_ikc_listen_param listen_param = {
.port = 501,
.handler = connect_handler,
.pkt_size = sizeof(struct ikc_scd_packet),
.queue_size = PAGE_SIZE,
.magic = 0x1129,
};
int prepare_ikc_channels(aal_os_t os)
{
struct aal_cpu_info *info;
info = aal_os_get_cpu_info(os);
if (!info) {
printk("Error: cannot retrieve CPU info.\n");
return -EINVAL;
}
if (info->n_cpus < 1) {
printk("Error: # of cpu is invalid.\n");
return -EINVAL;
}
num_channels = info->n_cpus;
channels = kzalloc(sizeof(struct mcctrl_channel) * num_channels,
GFP_KERNEL);
if (!channels) {
printk("Error: cannot allocate channels.\n");
return -ENOMEM;
}
aal_ikc_listen_port(os, &listen_param);
return 0;
}

View File

@ -3,10 +3,53 @@
#include <aal/aal_host_driver.h>
#include <uprotocol.h>
#include <linux/wait.h>
#define SCD_MSG_PREPARE_PROCESS 0x1
#define SCD_MSG_PREPARE_PROCESS_ACKED 0x2
#define SCD_MSG_SCHEDULE_PROCESS 0x3
#define SCD_MSG_INIT_CHANNEL 0x5
#define SCD_MSG_INIT_CHANNEL_ACKED 0x6
#define SCD_MSG_SYSCALL_ONESIDE 0x4
struct ikc_scd_packet {
int msg;
int ref;
unsigned long arg;
};
struct mcctrl_priv {
aal_os_t os;
struct program_load_desc *desc;
};
struct ikc_scd_init_param {
unsigned long request_page;
unsigned long response_page;
unsigned long doorbell_page;
};
struct syscall_params {
unsigned long request_pa;
struct syscall_request *request_va;
unsigned long response_rpa, response_pa;
struct syscall_response *response_va;
unsigned long doorbell_pa;
unsigned long *doorbell_va;
};
struct mcctrl_channel {
struct aal_ikc_channel_desc *c;
struct syscall_params param;
struct ikc_scd_init_param init;
int req;
wait_queue_head_t wq_syscall;
};
int mcctrl_ikc_send(int cpu, struct ikc_scd_packet *pisp);
#endif