From 261df92d0be88d619c24566055ac40e9efaa041c Mon Sep 17 00:00:00 2001 From: luojects Date: Wed, 12 Oct 2022 17:59:20 +0800 Subject: [PATCH] endpoint management: support multi endpoint * There are many endpoints creating from clientos, such as console/log endpoint, shell endpoint, message endpoint. linux should bind and manage them properly. * In OpenAMP, name, addr, dest_addr features are used to search endpoints, now we only use name, we will use more features to search in the future. * Messages are sended to linux constantly, linux creates a thread to deal with them. If it's ns_msg, linux calls ns_bind_cb, otherwise calls endpoint_cb. * fix bug: rmmod mcs_km.ko fail, or insmod mcs_km.ko twice fail. Signed-off-by: luojects --- mcs/mcs_km/mcs_km.c | 29 +++--- mcs/modules/openamp_module.c | 6 +- mcs/modules/remoteproc_module.c | 2 +- mcs/modules/rpmsg_module.c | 165 +++++++++++++++++++++++--------- mcs/modules/rpmsg_module.h | 12 ++- mcs/modules/virtio_module.c | 3 + mcs/modules/virtio_module.h | 1 + mcs/openamp_demo/rpmsg_main.c | 2 +- mcs/rpmsg_pty_demo/rpmsg_pty.c | 1 + 9 files changed, 154 insertions(+), 67 deletions(-) diff --git a/mcs/mcs_km/mcs_km.c b/mcs/mcs_km/mcs_km.c index f7a32af4..0445be1f 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 fbe385c3..89ba609a 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 2896ded1..8965040b 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 56ffb52f..9b1a78b2 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 9cba4780..93fb5c85 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 624822cf..4e5d5811 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 c73cdcb3..e8db4572 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 91e5e2e1..59d0258f 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 2d06c762..f95b80c5 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); -- Gitee