Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZyncMP Inter-Processor Interrupt / Interface API #231

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions examples/system/linux/zynqmp/zynqmp_amp_demo/CMakeLists.txt
Expand Up @@ -11,6 +11,41 @@ get_property (_ec_flgs GLOBAL PROPERTY "PROJECT_EC_FLAGS")
foreach (_app libmetal_amp_demo libmetal_amp_demod)
set (_src ${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c)
list(APPEND _src ${_src_common})
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/ipi-uio.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_atomic_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/ipi_shmem_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/ipi_latency_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_latency_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_throughput_demo.c)
if (WITH_SHARED_LIB)
add_executable (${_app}-share ${_src})
if (PROJECT_EC_FLAGS)
string(REPLACE " " ";" _ec_flgs ${PROJECT_EC_FLAGS})
target_compile_options (${_app}-share PUBLIC ${_ec_flgs})
endif (PROJECT_EC_FLAGS)
target_link_libraries (${_app}-share ${PROJECT_NAME}-shared ${_deps})
install (TARGETS ${_app}-share RUNTIME DESTINATION bin)
add_dependencies (${_app}-share ${PROJECT_NAME}-shared)
endif (WITH_SHARED_LIB)

if (WITH_STATIC_LIB)
if (${PROJECT_SYSTEM} STREQUAL "linux")
add_executable (${_app}-static ${_src})
if (PROJECT_EC_FLAGS)
string(REPLACE " " ";" _ec_flgs ${PROJECT_EC_FLAGS})
target_compile_options (${_app}-static PUBLIC ${_ec_flgs})
endif (PROJECT_EC_FLAGS)
target_link_libraries (${_app}-static ${PROJECT_NAME}-static ${_deps})
install (TARGETS ${_app}-static RUNTIME DESTINATION bin)
endif (${PROJECT_SYSTEM} STREQUAL "linux")
endif (WITH_STATIC_LIB)
endforeach (_app)

foreach (_app libmetal_amp_mb_shmem)
set (_src ${CMAKE_CURRENT_SOURCE_DIR}/libmetal_amp_demo.c)
list(APPEND _src ${_src_common})
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/ipi-mb.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/shmem_atomic_demo.c)
list(APPEND _src ${CMAKE_CURRENT_SOURCE_DIR}/ipi_shmem_demo.c)
Expand Down
39 changes: 37 additions & 2 deletions examples/system/linux/zynqmp/zynqmp_amp_demo/common.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
* Copyright (C) 2022, Advanced Micro Devices, Inc.
* Copyright (c) 2017-2022, Xilinx Inc. and Contributors. All rights reserved.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
Expand Down Expand Up @@ -196,4 +196,39 @@ static inline void print_demo(char *name)
LPRINTF("****** libmetal demo: %s ******\n", name);
}

/**
* @brief ipi_kick_register_handler() - register for IPI kick handler
*
* @param[in] hd - handler function
* @param[in] priv - private data will be passed to the handler
*/
void ipi_kick_register_handler(metal_irq_handler hd, void *priv);

/**
* @brief init_ipi() - Initialize IPI
*
* @return return 0 for success, negative value for failure.
*/
int init_ipi(void);

/**
* @brief deinit_ipi() - Deinitialize IPI
*/
void deinit_ipi(void);

/**
* @brief kick_ipi() - kick remote with IPI
*/
void kick_ipi(void *msg);

/**
* @brief disable_ipi_kick() - disable IPI interrupt from remote kick
*/
void disable_ipi_kick(void);

/**
* @brief enable_ipi_kick() - enable IPI interrupt from remote kick
*/
void enable_ipi_kick(void);

#endif /* __COMMON_H__ */
231 changes: 231 additions & 0 deletions examples/system/linux/zynqmp/zynqmp_amp_demo/ipi-mb.c
@@ -0,0 +1,231 @@
/*
* Copyright (c) 2017-2022, Xilinx Inc. and Contributors. All rights reserved.
* Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All Rights Reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <unistd.h>
#include <metal/atomic.h>
#include <metal/irq.h>
#include <metal/log.h>
#include <metal/sys.h>
#include "common.h"

#define RPROC_SYSFS "/sys/class/remoteproc/remoteproc0"
#define RPROC_SYSFS_KICK RPROC_SYSFS "/kick"
#define RPROC_SYSFS_REMOTE_KICK RPROC_SYSFS "/remote_kick"

struct ipi_channel {
char *kickf; /**< IPI kick sysfs path */
char *rkickf; /**< IPI remote kick sysfs path */
int rkick_fd; /**< IPI remote kick file descriptor */
atomic_int ipi_enabled; /**< flag to indicate if IPI is enabled */
atomic_int ipi_handling_wakeup; /**< IPI handling wakeup */
metal_irq_handler ipi_kick_cb; /**< IPI kick callback */
void *ipi_kick_priv; /**< IPI kick callback private data */
};

static struct ipi_channel ipi_chnl;
static pthread_t ipi_pthread;
static int ipi_handling_stop_fd;

/**
* @brief ipi_kick_handling() - IPI kick handling
*
* It will listening to the remote kick sysfs file.
* It will call the registered handler if there is a kick from the
* remote.
*
* @param[in] args - argument of pthread.
* @return NULL.
*
*/
static void *_ipi_kick_handling(void *args)
{
int rkick_fd;
sigset_t set;

(void)args;
/* unblock all signals */
sigfillset(&set);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
rkick_fd = ipi_chnl.rkick_fd;
while (1) {
char val[2] = {0, 0};
int ret;

lseek(rkick_fd, 0, SEEK_SET);
ret = read(rkick_fd, &val, sizeof(val));
if (ret < 0) {
LPERROR("failed to read %s.\n", ipi_chnl.rkickf);
return NULL;
}
if (val[0] == '1') {
if (atomic_load(&ipi_chnl.ipi_enabled) == 0) {
int v;

v = atomic_load(&ipi_chnl.ipi_handling_wakeup);
syscall(SYS_futex,
&ipi_chnl.ipi_handling_wakeup,
FUTEX_WAIT, v, NULL, NULL, 0);
}
if (ipi_chnl.ipi_kick_cb) {
ipi_chnl.ipi_kick_cb(rkick_fd,
ipi_chnl.ipi_kick_priv);
}
lseek(rkick_fd, 0, SEEK_SET);
ret = write(rkick_fd, &val, sizeof(val));
if (ret < 0) {
LPERROR("failed to write %s.\n",
ipi_chnl.rkickf);
return NULL;
}
} else {
struct pollfd fds[2];

fds[0].fd = rkick_fd;
fds[0].events = POLLPRI;
fds[1].fd = ipi_handling_stop_fd;
fds[1].events = POLLIN;
ret = poll(fds, 2, -1);
if (ret == 0) {
LPERROR("polling %s times out.\n",
ipi_chnl.rkickf);
return NULL;
} else if (fds[1].revents & POLLIN) {
return NULL;

} else if (ret < 0) {
LPERROR("polling %s failed, %s.\n",
ipi_chnl.rkickf, strerror(ret));
return NULL;
}
}
}
}

static void _enable_ipi_intr(struct ipi_channel *chnl)
{
int exp = 0;

atomic_compare_exchange_strong(&chnl->ipi_enabled, &exp, 1);
if (exp == 0) {
atomic_fetch_add(&chnl->ipi_handling_wakeup, 1);
syscall(SYS_futex, &chnl->ipi_handling_wakeup, FUTEX_WAKE,
1, NULL, NULL, 0);
}
}

static void _disable_ipi_intr(struct ipi_channel *chnl)
{
atomic_store(&chnl->ipi_enabled, 0);
}

void ipi_kick_register_handler(metal_irq_handler hd, void *priv)
{
ipi_chnl.ipi_kick_cb = hd;
ipi_chnl.ipi_kick_priv = priv;
}

int init_ipi(void)
{
int ret;
int val = 0;

atomic_init(&ipi_chnl.ipi_enabled, 0);
atomic_init(&ipi_chnl.ipi_handling_wakeup, 0);
ipi_chnl.kickf = RPROC_SYSFS_KICK;
ipi_chnl.rkickf = RPROC_SYSFS_REMOTE_KICK;

ret = open(ipi_chnl.rkickf, O_RDWR);
if (ret < 0) {
LPERROR("failed to open %s, %s.\n",
ipi_chnl.rkickf, strerror(ret));
return ret;
}
ipi_chnl.rkick_fd = ret;
/** Write to the remote kick fd to clear pending IPI interrupt */
ret = write(ipi_chnl.rkick_fd, &val, sizeof(val));
if (ret < 0) {
LPERROR("failed to write to %s, %s.\n",
ipi_chnl.rkickf, strerror(ret));
close(ipi_chnl.rkick_fd);
return ret;
}

ipi_handling_stop_fd = eventfd(0, 0);
if (ipi_handling_stop_fd < 0) {
LPERROR("failed to create ipi handling stop fd.\n");
close(ipi_chnl.rkick_fd);
return ipi_handling_stop_fd;
}

ret = pthread_create(&ipi_pthread, NULL, _ipi_kick_handling, NULL);
if (ret < 0) {
LPERROR("failed to create IPI handling thread.\n");
close(ipi_chnl.rkick_fd);
close(ipi_handling_stop_fd);
return ret;
}
return 0;
}

void deinit_ipi(void)
{
int ret;
uint64_t val = 1;

ret = write(ipi_handling_stop_fd, &val, sizeof(val));
if (ret < 0) {
LPERROR("failed to notify deinit ipi, %s.\n", strerror(ret));
}
atomic_fetch_add(&ipi_chnl.ipi_handling_wakeup, 1);
syscall(SYS_futex, &ipi_chnl.ipi_handling_wakeup, FUTEX_WAKE,
1, NULL, NULL, 0);
ret = pthread_join(ipi_pthread, NULL);
if (ret) {
LPERROR("failed to join IPI thread: %d.\n", ret);
}
close(ipi_handling_stop_fd);
close(ipi_chnl.rkick_fd);
}

void kick_ipi(void *msg)
{
int fd, ret;
int buf = -1;

(void)msg;
fd = open(ipi_chnl.kickf, O_WRONLY);
if (fd < 0) {
LPERROR("failed to open %s.\n", ipi_chnl.kickf);
return;
}

ret = write(fd, &buf, sizeof(buf));
if (ret <= 0)
LPERROR("failed to write to %s, %s.\n",
ipi_chnl.kickf, strerror(ret));
close(fd);
}

void disable_ipi_kick(void)
{
_disable_ipi_intr(&ipi_chnl);
}

void enable_ipi_kick(void)
{
_enable_ipi_intr(&ipi_chnl);
}