Skip to content

Commit

Permalink
examples: move rpmsg-mat-mul app from meta-openamp
Browse files Browse the repository at this point in the history
rpmsg-mat-mul application demonstrates simple IPC communication between
Host and Remote processor using rpmsg framework in linux kernel.
meta-openamp layer must contain only Yocto related files and not source files.
Move this application source code to openamp-system-reference repository.

Signed-off-by: Tanmay Shah <tanmay.shah@amd.com>
  • Loading branch information
tnmysh authored and arnopo committed Nov 15, 2022
1 parent 5d4b284 commit 8c15815
Show file tree
Hide file tree
Showing 2 changed files with 397 additions and 0 deletions.
18 changes: 18 additions & 0 deletions examples/linux/rpmsg-mat-mul/Makefile
@@ -0,0 +1,18 @@

APP = mat_mul_demo
APP_OBJS = mat_mul_demo.o

# Add any other object files to this list below


all: $(APP)

$(APP): $(APP_OBJS)
$(CC) $(LDFLAGS) -o $@ $(APP_OBJS) $(LDLIBS) -lpthread

clean:
rm -rf $(APP) *.o

%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<

379 changes: 379 additions & 0 deletions examples/linux/rpmsg-mat-mul/mat_mul_demo.c
@@ -0,0 +1,379 @@
//SPDX-License-Identifier: BSD-3-Clause

/*
* Sample demo application that showcases inter processor
* communication from linux userspace to a remote software
* context. The application generates random matrices and
* transmits them to the remote context over rpmsg. The
* remote application performs multiplication of matrices
* and transmits the results back to this application.
*/

#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <linux/rpmsg.h>

#define RPMSG_BUS_SYS "/sys/bus/rpmsg"

#define PR_DBG(fmt, args ...) printf("%s():%u "fmt, __func__, __LINE__, ##args)
#define SHUTDOWN_MSG 0xEF56A55A
#define MATRIX_SIZE 6

struct _matrix {
unsigned int size;
unsigned int elements[MATRIX_SIZE][MATRIX_SIZE];
};

static void matrix_print(struct _matrix *m)
{
int i, j;

/* Generate two random matrices */
printf(" \r\n Host : Linux : Printing results \r\n");

for (i = 0; i < m->size; ++i) {
for (j = 0; j < m->size; ++j)
printf(" %d ", (unsigned int)m->elements[i][j]);
printf("\r\n");
}
}

static void generate_matrices(int num_matrices,
unsigned int matrix_size, void *p_data)
{
int i, j, k;
struct _matrix *p_matrix = p_data;
time_t t;
unsigned long value;

srand((unsigned) time(&t));

for (i = 0; i < num_matrices; i++) {
/* Initialize workload */
p_matrix[i].size = matrix_size;

printf(" \r\n Host : Linux : Input matrix %d \r\n", i);
for (j = 0; j < matrix_size; j++) {
printf("\r\n");
for (k = 0; k < matrix_size; k++) {

value = (rand() & 0x7F);
value = value % 10;
p_matrix[i].elements[j][k] = value;
printf(" %d ",
(unsigned int)p_matrix[i].elements[j][k]);
}
}
printf("\r\n");
}

}

static int charfd = -1, fd;
static struct _matrix i_matrix[2];
static struct _matrix r_matrix;

void matrix_mult(int ntimes)
{
int i;

for (i=0; i < ntimes; i++){
generate_matrices(2, MATRIX_SIZE, i_matrix);

printf("%d: write rpmsg: %lu bytes\n", i, sizeof(i_matrix));
ssize_t rc = write(fd, i_matrix, sizeof(i_matrix));
if (rc < 0)
fprintf(stderr, "write,errno = %ld, %d\n", rc, errno);

puts("read results");
do {
rc = read(fd, &r_matrix, sizeof(r_matrix));
} while (rc < (int)sizeof(r_matrix));
matrix_print(&r_matrix);
printf("End of Matrix multiplication demo Round %d\n", i);
}
}

/*
* Probably an overkill to memset(.., sizeof(struct _matrix)) as
* the firmware looks for SHUTDOWN_MSG in the first 32 bits.
*/
void send_shutdown(int fd)
{
memset(i_matrix, SHUTDOWN_MSG, sizeof(struct _matrix));
if (write(fd, i_matrix, sizeof(i_matrix)) < 0)
perror("write SHUTDOWN_MSG\n");
}

int app_rpmsg_create_ept(int rpfd, struct rpmsg_endpoint_info *eptinfo)
{
int ret;

ret = ioctl(rpfd, RPMSG_CREATE_EPT_IOCTL, eptinfo);
if (ret)
perror("Failed to create endpoint.\n");
return ret;
}

static char *get_rpmsg_ept_dev_name(const char *rpmsg_char_name,
const char *ept_name,
char *ept_dev_name)
{
char sys_rpmsg_ept_name_path[64];
char svc_name[64];
char *sys_rpmsg_path = "/sys/class/rpmsg";
FILE *fp;
int i;
int ept_name_len;

for (i = 0; i < 128; i++) {
sprintf(sys_rpmsg_ept_name_path, "%s/%s/rpmsg%d/name",
sys_rpmsg_path, rpmsg_char_name, i);
printf("checking %s\n", sys_rpmsg_ept_name_path);
if (access(sys_rpmsg_ept_name_path, F_OK) < 0)
continue;
fp = fopen(sys_rpmsg_ept_name_path, "r");
if (!fp) {
printf("failed to open %s\n", sys_rpmsg_ept_name_path);
break;
}
fgets(svc_name, sizeof(svc_name), fp);
fclose(fp);
printf("svc_name: %s.\n",svc_name);
ept_name_len = strlen(ept_name);
if (ept_name_len > sizeof(svc_name))
ept_name_len = sizeof(svc_name);
if (!strncmp(svc_name, ept_name, ept_name_len)) {
sprintf(ept_dev_name, "rpmsg%d", i);
return ept_dev_name;
}
}

printf("Not able to RPMsg endpoint file for %s:%s.\n",
rpmsg_char_name, ept_name);
return NULL;
}

static int bind_rpmsg_chrdev(const char *rpmsg_dev_name)
{
char fpath[256];
char *rpmsg_chdrv = "rpmsg_chrdev";
int fd;
int ret;

/* rpmsg dev overrides path */
sprintf(fpath, "%s/devices/%s/driver_override",
RPMSG_BUS_SYS, rpmsg_dev_name);
PR_DBG("open %s\n", fpath);
fd = open(fpath, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open %s, %s\n",
fpath, strerror(errno));
return -EINVAL;
}
ret = write(fd, rpmsg_chdrv, strlen(rpmsg_chdrv) + 1);
if (ret < 0) {
fprintf(stderr, "Failed to write %s to %s, %s\n",
rpmsg_chdrv, fpath, strerror(errno));
return -EINVAL;
}
close(fd);

/* bind the rpmsg device to rpmsg char driver */
sprintf(fpath, "%s/drivers/%s/bind", RPMSG_BUS_SYS, rpmsg_chdrv);
fd = open(fpath, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open %s, %s\n",
fpath, strerror(errno));
return -EINVAL;
}
PR_DBG("write %s to %s\n", rpmsg_dev_name, fpath);
ret = write(fd, rpmsg_dev_name, strlen(rpmsg_dev_name) + 1);
if (ret < 0) {
fprintf(stderr, "Failed to write %s to %s, %s\n",
rpmsg_dev_name, fpath, strerror(errno));
return -EINVAL;
}
close(fd);
return 0;
}

static int get_rpmsg_chrdev_fd(const char *rpmsg_dev_name,
char *rpmsg_ctrl_name)
{
char dpath[2*NAME_MAX];
DIR *dir;
struct dirent *ent;
int fd;

sprintf(dpath, "%s/devices/%s/rpmsg", RPMSG_BUS_SYS, rpmsg_dev_name);
PR_DBG("opendir %s\n", dpath);
dir = opendir(dpath);
if (dir == NULL) {
fprintf(stderr, "opendir %s, %s\n", dpath, strerror(errno));
return -EINVAL;
}
while ((ent = readdir(dir)) != NULL) {
if (!strncmp(ent->d_name, "rpmsg_ctrl", 10)) {
sprintf(dpath, "/dev/%s", ent->d_name);
closedir(dir);
PR_DBG("open %s\n", dpath);
fd = open(dpath, O_RDWR | O_NONBLOCK);
if (fd < 0) {
fprintf(stderr, "open %s, %s\n",
dpath, strerror(errno));
return fd;
}
sprintf(rpmsg_ctrl_name, "%s", ent->d_name);
return fd;
}
}

fprintf(stderr, "No rpmsg_ctrl file found in %s\n", dpath);
closedir(dir);
return -EINVAL;
}

static void set_src_dst(char *out, struct rpmsg_endpoint_info *pep)
{
long dst = 0;
char *lastdot = strrchr(out, '.');

if (lastdot == NULL)
return;
dst = strtol(lastdot + 1, NULL, 10);
if ((errno == ERANGE && (dst == LONG_MAX || dst == LONG_MIN))
|| (errno != 0 && dst == 0)) {
return;
}
pep->dst = (unsigned int)dst;
}

/*
* return the first dirent matching rpmsg-openamp-demo-channel
* in /sys/bus/rpmsg/devices/ E.g.:
* virtio0.rpmsg-openamp-demo-channel.-1.1024
*/
static void lookup_channel(char *out, struct rpmsg_endpoint_info *pep)
{
char dpath[] = RPMSG_BUS_SYS "/devices";
struct dirent *ent;
DIR *dir = opendir(dpath);

if (dir == NULL) {
fprintf(stderr, "opendir %s, %s\n", dpath, strerror(errno));
return;
}
while ((ent = readdir(dir)) != NULL) {
if (strstr(ent->d_name, pep->name)) {
strncpy(out, ent->d_name, NAME_MAX);
set_src_dst(out, pep);
PR_DBG("using dev file: %s\n", out);
closedir(dir);
return;
}
}
closedir(dir);
fprintf(stderr, "No dev file for %s in %s\n", pep->name, dpath);
}

int main(int argc, char *argv[])
{
int ntimes = 1;
int opt, ret;
char rpmsg_dev[NAME_MAX] = "virtio0.rpmsg-openamp-demo-channel.-1.0";
char rpmsg_char_name[16];
char fpath[2*NAME_MAX];
struct rpmsg_endpoint_info eptinfo = {
.name = "rpmsg-openamp-demo-channel", .src = 0, .dst = 0
};
char ept_dev_name[16];
char ept_dev_path[32];

printf("\r\n Matrix multiplication demo start \r\n");

/* Load rpmsg_char driver */
printf("\r\nHost>probe rpmsg_char\r\n");
ret = system("set -x; lsmod; modprobe rpmsg_char");
if (ret < 0) {
perror("Failed to load rpmsg_char driver.\n");
return -EINVAL;
}
system("modprobe rpmsg_ctrl");

lookup_channel(rpmsg_dev, &eptinfo);

while ((opt = getopt(argc, argv, "d:n:s:e:")) != -1) {
switch (opt) {
case 'd':
strncpy(rpmsg_dev, optarg, sizeof(rpmsg_dev));
break;
case 'n':
ntimes = atoi(optarg);
break;
case 's':
eptinfo.src = atoi(optarg);
break;
case 'e':
eptinfo.dst = atoi(optarg);
break;
default:
printf("getopt return unsupported option: -%c\n",opt);
break;
}
}

sprintf(fpath, RPMSG_BUS_SYS "/devices/%s", rpmsg_dev);
if (access(fpath, F_OK)) {
fprintf(stderr, "access(%s): %s\n", fpath, strerror(errno));
return -EINVAL;
}
ret = bind_rpmsg_chrdev(rpmsg_dev);
if (ret < 0)
return ret;
charfd = get_rpmsg_chrdev_fd(rpmsg_dev, rpmsg_char_name);
if (charfd < 0)
return charfd;

/* Create endpoint from rpmsg char driver */
PR_DBG("app_rpmsg_create_ept: %s[src=%#x,dst=%#x]\n",
eptinfo.name, eptinfo.src, eptinfo.dst);
ret = app_rpmsg_create_ept(charfd, &eptinfo);
if (ret) {
fprintf(stderr, "app_rpmsg_create_ept %s\n", strerror(errno));
return -EINVAL;
}
if (!get_rpmsg_ept_dev_name(rpmsg_char_name, eptinfo.name,
ept_dev_name))
return -EINVAL;
sprintf(ept_dev_path, "/dev/%s", ept_dev_name);

printf("open %s\n", ept_dev_path);
fd = open(ept_dev_path, O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror(ept_dev_path);
close(charfd);
return -1;
}

PR_DBG("matrix_mult(%d)\n", ntimes);
matrix_mult(ntimes);

send_shutdown(fd);
close(fd);
if (charfd >= 0)
close(charfd);

printf("\r\n Quitting application .. \r\n");
printf(" Matrix multiply application end \r\n");

return 0;
}

0 comments on commit 8c15815

Please sign in to comment.