diff --git a/mcs/mcs_km/mcs_km.c b/mcs/mcs_km/mcs_km.c index f7a32af437edd752b05822c681d861adef07fef2..0445be1f13cdef65b1b532d67e45f468222798d3 100644 --- a/mcs/mcs_km/mcs_km.c +++ b/mcs/mcs_km/mcs_km.c @@ -50,16 +50,24 @@ static irqreturn_t handle_clientos_ipi(int irq, void *data) void set_openamp_ipi(void) { int err; - - err = request_percpu_irq(OPENAMP_IRQ, handle_clientos_ipi, "IPI", &cpu_number); - if (err) { - pr_err("mcs_km: request openamp irq failed(%d)\n", err); - return; + struct irq_desc *desc; + + /* use IRQ8 as IPI7, init irq resource once */ + desc = irq_to_desc(OPENAMP_IRQ); + if (!desc->action) { + err = request_percpu_irq(OPENAMP_IRQ, handle_clientos_ipi, "IPI", &cpu_number); + if (err) { + pr_err("mcs_km: request openamp irq failed(%d)\n", err); + return; + } } - preempt_disable(); /* fix kernel err message: using smp_processor_id() in preemptible */ - enable_percpu_irq(OPENAMP_IRQ, 0); - preempt_enable(); + /* In SMP, all the cores run Linux should be enabled */ + if (!irq_percpu_is_enabled(OPENAMP_IRQ)) { + preempt_disable(); /* fix kernel err message: using smp_processor_id() in preemptible */ + enable_percpu_irq(OPENAMP_IRQ, 0); + preempt_enable(); + } return; } @@ -320,11 +328,6 @@ module_init(mcs_dev_init); static void __exit mcs_dev_exit(void) { - preempt_disable(); - disable_percpu_irq(OPENAMP_IRQ); - preempt_enable(); - free_percpu_irq(OPENAMP_IRQ, &cpu_number); - device_destroy(mcs_class, MKDEV((unsigned int)mcs_major, 1)); class_destroy(mcs_class); unregister_chrdev(mcs_major, MCS_DEVICE_NAME); diff --git a/mcs/modules/openamp_module.c b/mcs/modules/openamp_module.c index fbe385c3da50f7b5c3ca59d47599214bb6d9ba74..89ba609a6be798317ddba92a07bf5adcea64e467 100644 --- a/mcs/modules/openamp_module.c +++ b/mcs/modules/openamp_module.c @@ -70,8 +70,6 @@ int openamp_init(void) { int ret; struct remoteproc *rproc; - unsigned char message[100]; - int len; int cpu_state; /* secondary core power state must be CPU_STATE_OFF, avoid initialize repeatedly */ @@ -99,10 +97,8 @@ int openamp_init(void) return ret; } - sleep(5); /* wait for clientos booting */ virtio_init(); - - (void)receive_message(message, sizeof(message), &len); /* name service: endpoint matching */ + rpmsg_module_init(); return 0; } diff --git a/mcs/modules/remoteproc_module.c b/mcs/modules/remoteproc_module.c index 2896ded1b45e8eacdd5993548f6feb72ed4818b9..8965040ba600f7f4511d27f5adc142b49a4cadec 100644 --- a/mcs/modules/remoteproc_module.c +++ b/mcs/modules/remoteproc_module.c @@ -72,7 +72,7 @@ static int rproc_start(struct remoteproc *rproc) static int rproc_stop(struct remoteproc *rproc) { - /* TODO: send message to clientos, clientos shut itself down by PSCI */ + /* TODO: send order to clientos by RPC service, clientos shut itself down by PSCI */ send_message("shutdown", sizeof("shutdown")); return 0; diff --git a/mcs/modules/rpmsg_module.c b/mcs/modules/rpmsg_module.c index 56ffb52fb36434d3b6221c6ada6fdc0fe007d3c7..9b1a78b24781230f80fbd5945d6666e9db555a07 100644 --- a/mcs/modules/rpmsg_module.c +++ b/mcs/modules/rpmsg_module.c @@ -1,100 +1,173 @@ #include #include #include +#include #include "virtio_module.h" #include "rpmsg_module.h" #define MCS_DEVICE_NAME "/dev/mcs" -static unsigned char received_data[2048] = {0}; -static unsigned int received_len = 0; -struct rpmsg_endpoint ept_inst; +/* endpoint state */ +#define ENDPOINT_BOUND 0 +#define ENDPOINT_NOT_FOUND -1 +#define ENDPOINT_UNKNOWN_STATE -2 -int endpoint_cb(struct rpmsg_endpoint *ept, void *data, - size_t len, uint32_t src, void *priv) +struct endpoint_priv { + unsigned char received_data[2048]; + unsigned int received_len; +}; + +/* TODO: endpoint ability negotiation */ +char ept_name[RPMSG_NAME_SIZE]; + +/* add more parameters such as dest_addr, when there are several clientos */ +static struct rpmsg_endpoint* obtain_endpoint(const char *name) +{ + struct metal_list *node; + struct rpmsg_endpoint *ept; + + metal_list_for_each(&rdev->endpoints, node) { + ept = metal_container_of(node, struct rpmsg_endpoint, node); + if (!strncmp(ept->name, name, sizeof(ept->name))) + return ept; + } + + return NULL; +} + +static int check_endpoint(const char *name) +{ + struct rpmsg_endpoint *ept = obtain_endpoint(name); + if (!ept) { + return ENDPOINT_NOT_FOUND; + } + + if ((ept->addr != RPMSG_ADDR_ANY) && (ept->dest_addr != RPMSG_ADDR_ANY)) + return ENDPOINT_BOUND; + + return ENDPOINT_UNKNOWN_STATE; +} + +static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv) { - memcpy(received_data + received_len, data, len); - received_len += len; + /* put data into endpoint's priv buffer, do not cover. + user call receive_message of this endpoint will read and clear the buffer */ + struct endpoint_priv *p = priv; + + memcpy(p->received_data + p->received_len, data, len); + p->received_len += len; return RPMSG_SUCCESS; } static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) { - (void)ept; - rpmsg_destroy_ept(&ept_inst); + rpmsg_destroy_ept(ept); +} + +void destroy_endpoint(const char *name) +{ + struct rpmsg_endpoint *ept = obtain_endpoint(name); + rpmsg_destroy_ept(ept); + free(ept->priv); + free(ept); } void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest) { - (void)rpmsg_create_ept(&ept_inst, rdev, name, - RPMSG_ADDR_ANY, dest, - endpoint_cb, - rpmsg_service_unbind); + strncpy(ept_name, name ? name : "", RPMSG_NAME_SIZE); + + /* endpoint_cb can be defined by user */ + struct rpmsg_endpoint *ept = malloc(sizeof(struct rpmsg_endpoint)); + ept->priv = malloc(sizeof(struct endpoint_priv)); + (void)rpmsg_create_ept(ept, rdev, ept_name, RPMSG_ADDR_ANY, dest, endpoint_cb, rpmsg_service_unbind); } -int receive_message(unsigned char *message, int message_len, int *real_len) +static void *rpmsg_receive_message(void *arg) { int ret; - int cpu_handler_fd; + int dev_fd; struct pollfd fds; - cpu_handler_fd = open(MCS_DEVICE_NAME, O_RDWR); - if (cpu_handler_fd < 0) { - printf("receive_message: open %s device failed.\n", MCS_DEVICE_NAME); - return cpu_handler_fd; + dev_fd = open(MCS_DEVICE_NAME, O_RDWR); + if (dev_fd < 0) { + printf("rpmsg_receive_message: open %s device failed.\n", MCS_DEVICE_NAME); + return (void*)-1; } - fds.fd = cpu_handler_fd; + fds.fd = dev_fd; fds.events = POLLIN; - /* clear the receive buffer */ - memset(received_data, 0, sizeof(received_data)); - received_len = 0; - while (1) { #ifdef DEBUG printf("master waiting for message....\n"); #endif - ret = poll(&fds, 1, 100); /* 100ms timeout */ + ret = poll(&fds, 1, -1); if (ret < 0) { - printf("receive_message: poll failed.\n"); - *real_len = 0; + printf("rpmsg_receive_message: poll failed.\n"); goto _cleanup; } - if (ret == 0) { -#ifdef DEBUG - printf("master waiting for message timeout....\n"); -#endif - break; - } - if (fds.revents & POLLIN) { #ifdef DEBUG printf("master receiving message....\n"); #endif - virtqueue_notification(vq[0]); /* will call endpoint_cb */ + virtqueue_notification(vq[0]); /* will call endpoint_cb or ns_bind_cb */ } } - if (received_len > message_len) { - printf("receive_message: buffer is too small.\n"); - *real_len = 0; - ret = -1; - goto _cleanup; +_cleanup: + close(dev_fd); + return (void*)0; +} + +int receive_message(unsigned char *message, int message_len, int *real_len) +{ + struct rpmsg_endpoint *ept = obtain_endpoint(ept_name); + if (!ept) { + printf("receive_message: no endpoint to receive message.\n"); + return -1; + } + + struct endpoint_priv *data = ept->priv; + if (data->received_len > message_len) { + printf("receive_message: buffer is too small. received_len:%d\n", data->received_len); + return -1; } + if (!message) + return -1; + /* copy buffer to message */ memset(message, 0, message_len); - memcpy(message, received_data, received_len); - *real_len = received_len; + memcpy(message, data->received_data, data->received_len); + *real_len = data->received_len; -_cleanup: - close(cpu_handler_fd); - return ret; + /* clear buffer */ + memset(data->received_data, 0, sizeof(data->received_data)); + data->received_len = 0; + + return 0; } int send_message(unsigned char *message, int len) { - return rpmsg_send(&ept_inst, message, len); + /* ensure endpoint is bound, sleep to wait */ + while (check_endpoint(ept_name) != ENDPOINT_BOUND) + usleep(1000); + + struct rpmsg_endpoint *ept = obtain_endpoint(ept_name); + return rpmsg_send(ept, message, len); +} + +void rpmsg_module_init(void) +{ + pthread_t tid; + + /* deal with messages received from clientos */ + if (pthread_create(&tid, NULL, rpmsg_receive_message, NULL) < 0) { + perror("rpmsg_receive_message pthread_create"); + return; + } + pthread_detach(tid); } diff --git a/mcs/modules/rpmsg_module.h b/mcs/modules/rpmsg_module.h index 9cba4780b2833785904ab83c7fccea2e9809b38b..93fb5c859d2edc88d0ad0fd76e9f6fcaf55832ef 100644 --- a/mcs/modules/rpmsg_module.h +++ b/mcs/modules/rpmsg_module.h @@ -3,7 +3,17 @@ #include -/* callback of ns */ +/* endpoint name */ +#define CONSOLE_ENDPOINT "console_ept" +#define LOG_ENDPOINT "log_ept" +#define SHELL_ENDPOINT "shell_ept" + +/* name service callback: create matching endpoint */ void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest); +/* destroy endpoint and inform clientos to destroy */ +void destroy_endpoint(const char *name); + +void rpmsg_module_init(void); + #endif \ No newline at end of file diff --git a/mcs/modules/virtio_module.c b/mcs/modules/virtio_module.c index 624822cfa0c6d3ecc04887252a8ce07c310b61c6..4e5d5811346cd0ed95ed95364273266f95386d7c 100644 --- a/mcs/modules/virtio_module.c +++ b/mcs/modules/virtio_module.c @@ -23,6 +23,7 @@ static struct rpmsg_virtio_device rvdev; static struct metal_io_region *io; struct virtqueue *vq[2]; static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; +struct rpmsg_device *rdev; static unsigned char virtio_get_status(struct virtio_device *vdev) { @@ -121,6 +122,8 @@ void virtio_init(void) free(io); return; } + + rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); } void virtio_deinit(void) diff --git a/mcs/modules/virtio_module.h b/mcs/modules/virtio_module.h index c73cdcb3ff978c5d770ebfed9989a27af5c041b4..e8db457214a5cbe85afad6241ae20542a7daa12a 100644 --- a/mcs/modules/virtio_module.h +++ b/mcs/modules/virtio_module.h @@ -30,5 +30,6 @@ void virtio_deinit(void); extern char *cpu_id; extern struct virtqueue *vq[2]; extern void *shmaddr; +extern struct rpmsg_device *rdev; #endif \ No newline at end of file diff --git a/mcs/openamp_demo/rpmsg_main.c b/mcs/openamp_demo/rpmsg_main.c index 91e5e2e1b7e5606a0c2c3d178e0912ec61194367..59d0258fa04ba9250dab9fcb9a2067344b670c05 100644 --- a/mcs/openamp_demo/rpmsg_main.c +++ b/mcs/openamp_demo/rpmsg_main.c @@ -15,7 +15,7 @@ static void cleanup(int sig) int rpmsg_app_master(void) { int ret; - int message = 0; + int message = 10; int len; printf("start processing OpenAMP demo...\n"); diff --git a/mcs/rpmsg_pty_demo/rpmsg_pty.c b/mcs/rpmsg_pty_demo/rpmsg_pty.c index 2d06c762cff51534150171e15e2a2abe7a133bd8..f95b80c54ed0fb6630ae8b42c27e60f709f95af7 100644 --- a/mcs/rpmsg_pty_demo/rpmsg_pty.c +++ b/mcs/rpmsg_pty_demo/rpmsg_pty.c @@ -75,6 +75,7 @@ void *shell_user(void *arg) pthread_mutex_lock(&mutex); ret = send_message(cmd, 1); /* send command to rtos */ + usleep(100 * 1000); /* wait 100ms, some messages may be seperated */ ret |= receive_message(reply, sizeof(reply), &reply_len); /* receive reply from rtos */ pthread_mutex_unlock(&mutex);