mirror of
https://github.com/OpenAMP/open-amp.git
synced 2026-02-06 02:54:32 +08:00
remoteproc: remove remoteproc drivers
Move remoteproc drivers implementation to applications' platform implementation. Signed-off-by: Wendy Liang <jliang@xilinx.com>
This commit is contained in:
@@ -2,4 +2,3 @@ collect (PROJECT_LIB_SOURCES elf_loader.c)
|
||||
collect (PROJECT_LIB_SOURCES remoteproc.c)
|
||||
collect (PROJECT_LIB_SOURCES remoteproc_virtio.c)
|
||||
collect (PROJECT_LIB_SOURCES rsc_table_parser.c)
|
||||
#add_subdirectory (drivers)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
if ("${MACHINE}" STREQUAL "zynqmp_r5")
|
||||
collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_a53.c)
|
||||
endif ("${MACHINE}" STREQUAL "zynqmp_r5")
|
||||
|
||||
if ("${MACHINE}" STREQUAL "zynq7")
|
||||
collect (PROJECT_LIB_SOURCES zynq_remoteproc_a9.c)
|
||||
collect (PROJECT_LIB_SOURCES zynq_a9_trampoline.S)
|
||||
endif ("${MACHINE}" STREQUAL "zynq7")
|
||||
|
||||
if ("${MACHINE}" STREQUAL "zynqmp")
|
||||
collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_r5.c)
|
||||
endif ("${MACHINE}" STREQUAL "zynqmp")
|
||||
|
||||
if ("${PROJECT_SYSTEM}" STREQUAL "linux")
|
||||
collect (PROJECT_LIB_SOURCES linux_remoteproc.c)
|
||||
endif ("${PROJECT_SYSTEM}" STREQUAL "linux")
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2016 Xilinx, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* zynqmp_remoteproc_r5.c
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file is the Implementation of IPC hardware layer interface
|
||||
* for Xilinx Zynq UltraScale+ MPSoC system.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/atomic.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/cpu.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <metal/assert.h>
|
||||
#include <metal/shmem.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <openamp/hil.h>
|
||||
#include <openamp/virtqueue.h>
|
||||
|
||||
#define MAX_VRING_MEM_SIZE 0x20000
|
||||
#define _rproc_wait() metal_cpu_yield()
|
||||
|
||||
#define UNIX_PREFIX "unix:"
|
||||
#define UNIXS_PREFIX "unixs:"
|
||||
|
||||
struct vring_ipi_info {
|
||||
/* Socket file path */
|
||||
char *path;
|
||||
int fd;
|
||||
struct metal_io_region *vring_io;
|
||||
atomic_int sync;
|
||||
};
|
||||
|
||||
/*--------------------------- Declare Functions ------------------------ */
|
||||
static int _ipi_handler(int vect_id, void *data);
|
||||
static int _enable_interrupt(struct proc_intr *intr);
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
|
||||
static void _shutdown_cpu(struct hil_proc *proc);
|
||||
static int _poll(struct hil_proc *proc, int nonblock);
|
||||
static int _initialize(struct hil_proc *proc);
|
||||
static void _release(struct hil_proc *proc);
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev);
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io);
|
||||
|
||||
|
||||
/*--------------------------- Globals ---------------------------------- */
|
||||
struct hil_platform_ops linux_proc_ops = {
|
||||
.enable_interrupt = _enable_interrupt,
|
||||
.notify = _notify,
|
||||
.boot_cpu = _boot_cpu,
|
||||
.shutdown_cpu = _shutdown_cpu,
|
||||
.poll = _poll,
|
||||
.alloc_shm = _alloc_shm,
|
||||
.release_shm = _release_shm,
|
||||
.initialize = _initialize,
|
||||
.release = _release,
|
||||
};
|
||||
|
||||
static int sk_unix_client(const char *descr)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
memset(&addr, 0, sizeof addr);
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX),
|
||||
sizeof addr.sun_path);
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
|
||||
printf("connected to %s\n", descr + strlen(UNIX_PREFIX));
|
||||
return fd;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sk_unix_server(const char *descr)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int fd, nfd;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, descr + strlen(UNIXS_PREFIX),
|
||||
sizeof addr.sun_path);
|
||||
unlink(addr.sun_path);
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
listen(fd, 5);
|
||||
printf("Waiting for connection on %s\n", addr.sun_path);
|
||||
nfd = accept(fd, NULL, NULL);
|
||||
close(fd);
|
||||
return nfd;
|
||||
fail:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int event_open(const char *descr)
|
||||
{
|
||||
int fd = -1;
|
||||
int i;
|
||||
|
||||
if (descr == NULL) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (memcmp(UNIX_PREFIX, descr, strlen(UNIX_PREFIX)) == 0) {
|
||||
/* UNIX. Retry to connect a few times to give the peer a
|
||||
* chance to setup. */
|
||||
for (i = 0; i < 100 && fd == -1; i++) {
|
||||
fd = sk_unix_client(descr);
|
||||
if (fd == -1)
|
||||
usleep(i * 10 * 1000);
|
||||
}
|
||||
}
|
||||
if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)) == 0) {
|
||||
/* UNIX. */
|
||||
fd = sk_unix_server(descr);
|
||||
}
|
||||
printf("Open IPI: %s\n", descr);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int _ipi_handler(int vect_id, void *data)
|
||||
{
|
||||
char dummy_buf[32];
|
||||
struct proc_intr *intr = data;
|
||||
struct vring_ipi_info *ipi = intr->data;
|
||||
|
||||
(void) vect_id;
|
||||
|
||||
read(vect_id, dummy_buf, sizeof(dummy_buf));
|
||||
atomic_flag_clear(&ipi->sync);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _enable_interrupt(struct proc_intr *intr)
|
||||
{
|
||||
struct vring_ipi_info *ipi = intr->data;
|
||||
|
||||
ipi->fd = event_open(ipi->path);
|
||||
if (ipi->fd < 0) {
|
||||
fprintf(stderr, "ERROR: Failed to open sock %s for IPI.\n",
|
||||
ipi->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intr->vect_id = ipi->fd;
|
||||
|
||||
/* Register ISR */
|
||||
metal_irq_register(ipi->fd, _ipi_handler,
|
||||
NULL, intr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
|
||||
{
|
||||
|
||||
(void)proc;
|
||||
struct vring_ipi_info *ipi = (struct vring_ipi_info *)(intr_info->data);
|
||||
if (ipi == NULL)
|
||||
return;
|
||||
|
||||
char dummy = 1;
|
||||
send(ipi->fd, &dummy, 1, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
|
||||
{
|
||||
(void)proc;
|
||||
(void)load_addr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _shutdown_cpu(struct hil_proc *proc)
|
||||
{
|
||||
(void)proc;
|
||||
return;
|
||||
}
|
||||
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev)
|
||||
{
|
||||
(void)proc;
|
||||
(void)pa;
|
||||
(void)size;
|
||||
|
||||
*dev = NULL;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io)
|
||||
{
|
||||
(void)proc;
|
||||
(void)io;
|
||||
hil_close_generic_mem_dev(dev);
|
||||
}
|
||||
|
||||
static int _poll(struct hil_proc *proc, int nonblock)
|
||||
{
|
||||
(void) nonblock;
|
||||
struct proc_vring *vring;
|
||||
struct vring_ipi_info *ipi;
|
||||
unsigned int flags;
|
||||
|
||||
int num_vrings = proc->vdev.num_vrings;
|
||||
int ret = 0;
|
||||
int notified;
|
||||
int i;
|
||||
|
||||
metal_assert(proc);
|
||||
|
||||
notified = 0;
|
||||
while (1) {
|
||||
for (i = 0; i < num_vrings; i++) {
|
||||
vring = &proc->vdev.vring_info[i];
|
||||
ipi = (struct vring_ipi_info *)(vring->intr_info.data);
|
||||
flags = metal_irq_save_disable();
|
||||
if (!(atomic_flag_test_and_set(&ipi->sync))) {
|
||||
metal_irq_restore_enable(flags);
|
||||
virtqueue_notification(vring->vq);
|
||||
notified = 1;
|
||||
} else {
|
||||
metal_irq_restore_enable(flags);
|
||||
}
|
||||
}
|
||||
if (notified)
|
||||
return 0;
|
||||
if (nonblock)
|
||||
return -EAGAIN;
|
||||
_rproc_wait();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief _adjust_vring_io - Adjust the vring I/O region to map to the
|
||||
* specified start device address.
|
||||
* @param[in] io - vring I/O region
|
||||
* @param[in] start_phy - start device address of the vring, this is
|
||||
* not the actual physical address.
|
||||
* @return adjusted I/O region
|
||||
*/
|
||||
static struct metal_io_region *_create_vring_io(struct metal_io_region *in_io,
|
||||
int start_phy)
|
||||
{
|
||||
struct metal_io_region *io = 0;
|
||||
metal_phys_addr_t *phys;
|
||||
io = metal_allocate_memory(sizeof(struct metal_io_region));
|
||||
if (!io) {
|
||||
fprintf(stderr, "ERROR: Failed to allocation I/O for vring.\n");
|
||||
return NULL;
|
||||
}
|
||||
phys = metal_allocate_memory(sizeof(metal_phys_addr_t));
|
||||
if (!phys) {
|
||||
fprintf(stderr, "ERROR: Failed to allocation phys for vring.\n");
|
||||
metal_free_memory(io);
|
||||
return NULL;
|
||||
}
|
||||
*phys = (metal_phys_addr_t)start_phy;
|
||||
metal_io_init(io, in_io->virt, phys, in_io->size,
|
||||
sizeof(metal_phys_addr_t)*8 - 1, 0, NULL);
|
||||
return io;
|
||||
}
|
||||
|
||||
static int _initialize(struct hil_proc *proc)
|
||||
{
|
||||
struct proc_vring *vring;
|
||||
struct vring_ipi_info *ipi;
|
||||
struct metal_io_region *io;
|
||||
int i;
|
||||
if (proc) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
vring = &proc->vdev.vring_info[i];
|
||||
ipi = (struct vring_ipi_info *)vring->intr_info.data;
|
||||
if (ipi && !ipi->vring_io && vring->io) {
|
||||
io = _create_vring_io(vring->io, 0);
|
||||
if (!io)
|
||||
return -1;
|
||||
ipi->vring_io = vring->io;
|
||||
vring->io = io;
|
||||
atomic_store(&ipi->sync, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _release(struct hil_proc *proc)
|
||||
{
|
||||
struct proc_vring *vring;
|
||||
struct vring_ipi_info *ipi;
|
||||
int i;
|
||||
if (proc) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
vring = &proc->vdev.vring_info[i];
|
||||
ipi = (struct vring_ipi_info *)vring->intr_info.data;
|
||||
if (ipi) {
|
||||
if (ipi->fd >= 0) {
|
||||
metal_irq_unregister(ipi->fd, 0, NULL,
|
||||
vring);
|
||||
close(ipi->fd);
|
||||
}
|
||||
if (ipi->vring_io) {
|
||||
metal_free_memory(vring->io->physmap);
|
||||
metal_free_memory(vring->io);
|
||||
vring->io = NULL;
|
||||
if (ipi->vring_io->ops.close)
|
||||
ipi->vring_io->ops.close(ipi->vring_io);
|
||||
ipi->vring_io = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
.global zynq_trampoline
|
||||
zynq_trampoline:
|
||||
ldr r0, [pc]
|
||||
bx r0
|
||||
.global zynq_trampoline_jump
|
||||
zynq_trampoline_jump:
|
||||
.word
|
||||
.global zynq_trampoline_end
|
||||
zynq_trampoline_end:
|
||||
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* platform.c
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file is the Implementation of IPC hardware layer interface
|
||||
* for Xilinx Zynq ZC702EVK platform.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <openamp/hil.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/atomic.h>
|
||||
|
||||
/* ------------------------- Macros --------------------------*/
|
||||
#define SCUGIC_PERIPH_BASE 0xF8F00000
|
||||
#define SCUGIC_DIST_BASE (SCUGIC_PERIPH_BASE + 0x00001000)
|
||||
#define ESAL_DP_SLCR_BASE 0xF8000000
|
||||
#define GIC_DIST_SOFTINT 0xF00
|
||||
#define GIC_SFI_TRIG_CPU_MASK 0x00FF0000
|
||||
#define GIC_SFI_TRIG_SATT_MASK 0x00008000
|
||||
#define GIC_SFI_TRIG_INTID_MASK 0x0000000F
|
||||
#define GIC_CPU_ID_BASE (1 << 4)
|
||||
#define A9_CPU_SLCR_RESET_CTRL 0x244
|
||||
#define A9_CPU_SLCR_CLK_STOP (1 << 4)
|
||||
#define A9_CPU_SLCR_RST (1 << 0)
|
||||
|
||||
#define unlock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x08, 0xDF0DDF0D)
|
||||
#define lock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x04, 0x767B767B)
|
||||
|
||||
/* L2Cpl310 L2 cache controller base address. */
|
||||
#define HIL_PL130_BASE 0xF8F02000
|
||||
|
||||
/********************/
|
||||
/* Register offsets */
|
||||
/********************/
|
||||
|
||||
#define HIL_PL130_INVALLINE 0x770
|
||||
#define HIL_PL130_CLEANINVLINE 0x7F0
|
||||
|
||||
|
||||
#define HIL_PA_SBZ_MASK ~(HIL_CACHE_LINE_SIZE - 1UL)
|
||||
#define HIL_CACHE_LINE_SIZE 32
|
||||
#define HIL_CACHE_INV_ALL_WAYS 0xFF
|
||||
#define HIL_CACHE_UNLOCK_ALL_WAYS 0xFFFF0000
|
||||
#define HIL_CACHE_CLEAR_INT 0x1FF
|
||||
|
||||
/* Memory attributes */
|
||||
#define NORM_NONCACHE 0x11DE2 /* Normal Non-cacheable */
|
||||
#define STRONG_ORDERED 0xC02 /* Strongly ordered */
|
||||
#define DEVICE_MEMORY 0xC06 /* Device memory */
|
||||
#define RESERVED 0x0 /* reserved memory */
|
||||
|
||||
#define HIL_DEV_NAME_PREFIX "hil-dev."
|
||||
|
||||
#define _rproc_wait() asm volatile("wfi")
|
||||
|
||||
/*--------------------------- Declare Functions ------------------------ */
|
||||
static int _enable_interrupt(struct proc_intr *intr);
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
|
||||
static void _shutdown_cpu(struct hil_proc *proc);
|
||||
static int _poll(struct hil_proc *proc, int nonblock);
|
||||
static int _initialize(struct hil_proc *proc);
|
||||
static void _release(struct hil_proc *proc);
|
||||
static int _ipi_handler(int vect_id, void *data);
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev);
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io);
|
||||
|
||||
/*--------------------------- Globals ---------------------------------- */
|
||||
struct hil_platform_ops zynq_a9_proc_ops = {
|
||||
.enable_interrupt = _enable_interrupt,
|
||||
.notify = _notify,
|
||||
.boot_cpu = _boot_cpu,
|
||||
.shutdown_cpu = _shutdown_cpu,
|
||||
.poll = _poll,
|
||||
.alloc_shm = _alloc_shm,
|
||||
.release_shm = _release_shm,
|
||||
.initialize = _initialize,
|
||||
.release = _release,
|
||||
};
|
||||
|
||||
struct hil_mem_device {
|
||||
struct metal_device device;
|
||||
char name[64];
|
||||
metal_phys_addr_t pa;
|
||||
};
|
||||
|
||||
static metal_phys_addr_t git_dist_base_addr = SCUGIC_DIST_BASE;
|
||||
static struct metal_io_region gic_dist_io = {
|
||||
(void *)SCUGIC_DIST_BASE,
|
||||
&git_dist_base_addr,
|
||||
0x1000,
|
||||
(sizeof(metal_phys_addr_t) << 3),
|
||||
(metal_phys_addr_t)(-1),
|
||||
0,
|
||||
{NULL},
|
||||
};
|
||||
|
||||
//volatile unsigned int ipi_counter = 0;
|
||||
//volatile unsigned int enableirq_counter = 0;
|
||||
|
||||
int _ipi_handler(int vect_id, void *data)
|
||||
{
|
||||
struct proc_intr *intr_info = data;
|
||||
|
||||
(void) vect_id;
|
||||
|
||||
atomic_flag_clear((atomic_uint *)&(intr_info->data));
|
||||
|
||||
//ipi_counter++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _enable_interrupt(struct proc_intr *intr)
|
||||
{
|
||||
//enableirq_counter++;
|
||||
/* Register ISR */
|
||||
metal_irq_register(intr->vect_id, _ipi_handler,
|
||||
intr->dev, intr);
|
||||
|
||||
/* Enable the interrupts */
|
||||
metal_irq_enable(intr->vect_id);
|
||||
|
||||
/* FIXME: This is a workaround for Zynq. As Linux is possible
|
||||
* to have already generate the soft IRQ
|
||||
*/
|
||||
atomic_flag_clear((atomic_uint *)&(intr->data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
|
||||
mask = ((1 << (GIC_CPU_ID_BASE + proc->cpu_id)) | (intr_info->vect_id))
|
||||
& (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
|
||||
|
||||
/* Trigger IPI */
|
||||
metal_io_write32(&gic_dist_io, GIC_DIST_SOFTINT, mask);
|
||||
}
|
||||
|
||||
static int _poll(struct hil_proc *proc, int nonblock)
|
||||
{
|
||||
struct proc_vring *vring;
|
||||
unsigned int flags;
|
||||
struct proc_intr *intr_info;
|
||||
int i = 0;
|
||||
int kicked = 0;
|
||||
|
||||
while(1) {
|
||||
vring = &proc->vdev.vring_info[i];
|
||||
intr_info = &(vring->intr_info);
|
||||
flags = metal_irq_save_disable();
|
||||
if (!(atomic_flag_test_and_set(
|
||||
(atomic_uint *)&(intr_info->data)))) {
|
||||
metal_irq_restore_enable(flags);
|
||||
virtqueue_notification(vring->vq);
|
||||
kicked = 1;
|
||||
if (i)
|
||||
return 0;
|
||||
i++;
|
||||
} else if (!i) {
|
||||
metal_irq_restore_enable(flags);
|
||||
i++;
|
||||
} else {
|
||||
if (kicked) {
|
||||
metal_irq_restore_enable(flags);
|
||||
return 0;
|
||||
} else if (nonblock) {
|
||||
metal_irq_restore_enable(flags);
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
_rproc_wait();
|
||||
metal_irq_restore_enable(flags);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern char zynq_trampoline;
|
||||
extern char zynq_trampoline_jump;
|
||||
extern char zynq_trampoline_end;
|
||||
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
|
||||
{
|
||||
/* FIXME: Will need to add the boot_cpu implementation back */
|
||||
#if 0
|
||||
unsigned int reg;
|
||||
unsigned int tramp_size;
|
||||
unsigned int tramp_addr = 0;
|
||||
|
||||
if (load_addr) {
|
||||
tramp_size = zynq_trampoline_end - zynq_trampoline;
|
||||
if ((load_addr < tramp_size) || (load_addr & 0x3)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
|
||||
|
||||
/*
|
||||
* Trampoline code is copied to address 0 from where remote core is expected to
|
||||
* fetch first instruction after reset.If master is using the address 0 then
|
||||
* this mem copy will screwed the system. It is user responsibility to not
|
||||
* copy trampoline code in such cases.
|
||||
*
|
||||
*/
|
||||
memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
|
||||
/* Write image address at the word reserved at the trampoline end */
|
||||
HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
|
||||
}
|
||||
|
||||
unlock_slcr();
|
||||
|
||||
reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
|
||||
reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
|
||||
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
|
||||
/* De-assert reset signal and start clock to start the core */
|
||||
reg &= ~(A9_CPU_SLCR_RST << cpu_id);
|
||||
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
|
||||
|
||||
lock_slcr();
|
||||
|
||||
#else
|
||||
(void)proc;
|
||||
(void)load_addr;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _shutdown_cpu(struct hil_proc *proc)
|
||||
{
|
||||
/* FIXME: Will need to add the shutdown CPU implementation back */
|
||||
#if 0
|
||||
unsigned int reg;
|
||||
|
||||
unlock_slcr();
|
||||
|
||||
reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
|
||||
/* Assert reset signal and stop clock to halt the core */
|
||||
reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
|
||||
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
|
||||
|
||||
lock_slcr();
|
||||
#else
|
||||
(void)proc;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev)
|
||||
{
|
||||
(void)proc;
|
||||
|
||||
*dev = hil_create_generic_mem_dev(pa, size,
|
||||
NORM_NONCACHE | STRONG_ORDERED);
|
||||
if ((*dev))
|
||||
return &((*dev)->regions[0]);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io)
|
||||
{
|
||||
(void)proc;
|
||||
(void)io;
|
||||
hil_close_generic_mem_dev(dev);
|
||||
}
|
||||
|
||||
static int _initialize(struct hil_proc *proc)
|
||||
{
|
||||
int i;
|
||||
struct proc_intr *intr_info;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
intr_info = &(proc->vdev.vring_info[i].intr_info);
|
||||
atomic_store((atomic_uint *)&(intr_info->data), 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _release(struct hil_proc *proc)
|
||||
{
|
||||
(void)proc;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* platform.c
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file is the Implementation of IPC hardware layer interface
|
||||
* for Xilinx Zynq ZC702EVK platform.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/atomic.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <openamp/hil.h>
|
||||
#include <openamp/virtqueue.h>
|
||||
|
||||
/* IPI REGs OFFSET */
|
||||
#define IPI_TRIG_OFFSET 0x00000000 /* IPI trigger register offset */
|
||||
#define IPI_OBS_OFFSET 0x00000004 /* IPI observation register offset */
|
||||
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
|
||||
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
|
||||
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
|
||||
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
|
||||
|
||||
/* memory attributes */
|
||||
#define DEVICE_SHARED 0x00000001U /*device, shareable*/
|
||||
#define DEVICE_NONSHARED 0x00000010U /*device, non shareable*/
|
||||
#define NORM_NSHARED_NCACHE 0x00000008U /* Non cacheable non shareable */
|
||||
#define NORM_SHARED_NCACHE 0x0000000CU /* Non cacheable shareable */
|
||||
#define PRIV_RW_USER_RW (0x00000003U<<8U) /*Full Access*/
|
||||
|
||||
#define _rproc_wait() asm volatile("wfi")
|
||||
|
||||
/* -- FIX ME: ipi info is to be defined -- */
|
||||
struct ipi_info {
|
||||
const char *name;
|
||||
const char *bus_name;
|
||||
struct metal_device *dev;
|
||||
struct metal_io_region *io;
|
||||
metal_phys_addr_t paddr;
|
||||
uint32_t ipi_chn_mask;
|
||||
int registered;
|
||||
atomic_int sync;
|
||||
};
|
||||
|
||||
/*--------------------------- Declare Functions ------------------------ */
|
||||
static int _enable_interrupt(struct proc_intr *intr);
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
|
||||
static void _shutdown_cpu(struct hil_proc *proc);
|
||||
static int _poll(struct hil_proc *proc, int nonblock);
|
||||
static int _initialize(struct hil_proc *proc);
|
||||
static void _release(struct hil_proc *proc);
|
||||
|
||||
static int _ipi_handler(int vect_id, void *data);
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev);
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io);
|
||||
|
||||
/*--------------------------- Globals ---------------------------------- */
|
||||
struct hil_platform_ops zynqmp_r5_a53_proc_ops = {
|
||||
.enable_interrupt = _enable_interrupt,
|
||||
.notify = _notify,
|
||||
.boot_cpu = _boot_cpu,
|
||||
.shutdown_cpu = _shutdown_cpu,
|
||||
.poll = _poll,
|
||||
.alloc_shm = _alloc_shm,
|
||||
.release_shm = _release_shm,
|
||||
.initialize = _initialize,
|
||||
.release = _release,
|
||||
};
|
||||
|
||||
int _ipi_handler(int vect_id, void *data)
|
||||
{
|
||||
struct proc_intr *intr = data;
|
||||
struct ipi_info *ipi = intr->data;
|
||||
struct metal_io_region *io = ipi->io;
|
||||
unsigned int ipi_intr_status =
|
||||
(unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
|
||||
|
||||
(void) vect_id;
|
||||
|
||||
if (ipi_intr_status & ipi->ipi_chn_mask) {
|
||||
atomic_flag_clear(&ipi->sync);
|
||||
metal_io_write32(io, IPI_ISR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _enable_interrupt(struct proc_intr *intr)
|
||||
{
|
||||
struct ipi_info *ipi =
|
||||
(struct ipi_info *)(intr->data);
|
||||
struct metal_io_region *io = ipi->io;
|
||||
|
||||
if (ipi->registered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register ISR */
|
||||
metal_irq_register(intr->vect_id, _ipi_handler,
|
||||
intr->dev, intr);
|
||||
/* Enable IPI interrupt */
|
||||
metal_irq_enable(intr->vect_id);
|
||||
metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask);
|
||||
ipi->registered = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
|
||||
{
|
||||
|
||||
(void)proc;
|
||||
struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
|
||||
if (ipi == NULL)
|
||||
return;
|
||||
|
||||
/* Trigger IPI */
|
||||
metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
|
||||
}
|
||||
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
|
||||
{
|
||||
(void)proc;
|
||||
(void)load_addr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _shutdown_cpu(struct hil_proc *proc)
|
||||
{
|
||||
(void)proc;
|
||||
return;
|
||||
}
|
||||
|
||||
static int _poll(struct hil_proc *proc, int nonblock)
|
||||
{
|
||||
struct proc_vdev *vdev;
|
||||
struct ipi_info *ipi;
|
||||
unsigned int flags;
|
||||
|
||||
vdev = &proc->vdev;
|
||||
ipi = (struct ipi_info *)(vdev->intr_info.data);
|
||||
while(1) {
|
||||
flags = metal_irq_save_disable();
|
||||
if (!(atomic_flag_test_and_set(&ipi->sync))) {
|
||||
metal_irq_restore_enable(flags);
|
||||
hil_notified(proc, (uint32_t)(-1));
|
||||
return 0;
|
||||
}
|
||||
if (nonblock) {
|
||||
metal_irq_restore_enable(flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
_rproc_wait();
|
||||
metal_irq_restore_enable(flags);
|
||||
}
|
||||
}
|
||||
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev)
|
||||
{
|
||||
(void)proc;
|
||||
|
||||
*dev = hil_create_generic_mem_dev(pa, size,
|
||||
NORM_SHARED_NCACHE | PRIV_RW_USER_RW);
|
||||
if ((*dev))
|
||||
return &((*dev)->regions[0]);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io)
|
||||
{
|
||||
(void)proc;
|
||||
(void)io;
|
||||
hil_close_generic_mem_dev(dev);
|
||||
}
|
||||
|
||||
static int _initialize(struct hil_proc *proc)
|
||||
{
|
||||
int ret;
|
||||
struct proc_intr *intr_info;
|
||||
struct ipi_info *ipi;
|
||||
|
||||
if (!proc)
|
||||
return -1;
|
||||
|
||||
intr_info = &(proc->vdev.intr_info);
|
||||
ipi = intr_info->data;
|
||||
|
||||
if (ipi && ipi->name && ipi->bus_name) {
|
||||
ret = metal_device_open(ipi->bus_name, ipi->name,
|
||||
&ipi->dev);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
ipi->io = metal_device_io_region(ipi->dev, 0);
|
||||
} else if (ipi->paddr) {
|
||||
ipi->io = metal_allocate_memory(
|
||||
sizeof(struct metal_io_region));
|
||||
if (!ipi->io)
|
||||
goto error;
|
||||
metal_io_init(ipi->io, (void *)ipi->paddr,
|
||||
&ipi->paddr, 0x1000,
|
||||
sizeof(metal_phys_addr_t) << 3,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (ipi->io) {
|
||||
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
atomic_store(&ipi->sync, 1);
|
||||
}
|
||||
ipi->registered = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
_release(proc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _release(struct hil_proc *proc)
|
||||
{
|
||||
struct proc_intr *intr_info;
|
||||
struct ipi_info *ipi;
|
||||
|
||||
if (!proc)
|
||||
return;
|
||||
intr_info = &(proc->vdev.intr_info);
|
||||
ipi = (struct ipi_info *)(intr_info->data);
|
||||
if (ipi) {
|
||||
if (ipi->io) {
|
||||
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
if (ipi->dev) {
|
||||
metal_device_close(ipi->dev);
|
||||
ipi->dev = NULL;
|
||||
} else {
|
||||
metal_free_memory(ipi->io);
|
||||
}
|
||||
ipi->io = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* zynqmp_remoteproc_r5.c
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file is the Implementation of IPC hardware layer interface
|
||||
* for Xilinx Zynq UltraScale+ MPSoC system.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/atomic.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/cpu.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <openamp/hil.h>
|
||||
#include <openamp/virtqueue.h>
|
||||
|
||||
/* IPI REGs OFFSET */
|
||||
#define IPI_TRIG_OFFSET 0x00000000 /** IPI trigger register offset */
|
||||
#define IPI_OBS_OFFSET 0x00000004 /** IPI observation register offset */
|
||||
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
|
||||
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
|
||||
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
|
||||
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
|
||||
|
||||
#define _rproc_wait() metal_cpu_yield()
|
||||
|
||||
/* -- FIX ME: ipi info is to be defined -- */
|
||||
struct ipi_info {
|
||||
const char *name;
|
||||
const char *bus_name;
|
||||
struct metal_device *dev;
|
||||
struct metal_io_region *io;
|
||||
metal_phys_addr_t paddr;
|
||||
uint32_t ipi_chn_mask;
|
||||
atomic_int sync;
|
||||
};
|
||||
|
||||
/*--------------------------- Declare Functions ------------------------ */
|
||||
static int _enable_interrupt(struct proc_intr *intr);
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
|
||||
static void _shutdown_cpu(struct hil_proc *proc);
|
||||
static int _poll(struct hil_proc *proc, int nonblock);
|
||||
static int _initialize(struct hil_proc *proc);
|
||||
static void _release(struct hil_proc *proc);
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev);
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io);
|
||||
|
||||
/*--------------------------- Globals ---------------------------------- */
|
||||
struct hil_platform_ops zynqmp_a53_r5_proc_ops = {
|
||||
.enable_interrupt = _enable_interrupt,
|
||||
.notify = _notify,
|
||||
.boot_cpu = _boot_cpu,
|
||||
.shutdown_cpu = _shutdown_cpu,
|
||||
.poll = _poll,
|
||||
.alloc_shm = _alloc_shm,
|
||||
.release_shm = _release_shm,
|
||||
.initialize = _initialize,
|
||||
.release = _release,
|
||||
};
|
||||
|
||||
static int _enable_interrupt(struct proc_intr *intr)
|
||||
{
|
||||
(void)intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
|
||||
{
|
||||
|
||||
(void)proc;
|
||||
struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
|
||||
if (ipi == NULL)
|
||||
return;
|
||||
|
||||
/* Trigger IPI */
|
||||
metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
|
||||
}
|
||||
|
||||
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
|
||||
{
|
||||
(void)proc;
|
||||
(void)load_addr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _shutdown_cpu(struct hil_proc *proc)
|
||||
{
|
||||
(void)proc;
|
||||
return;
|
||||
}
|
||||
|
||||
static int _poll(struct hil_proc *proc, int nonblock)
|
||||
{
|
||||
struct proc_vdev *vdev;
|
||||
struct ipi_info *ipi;
|
||||
struct metal_io_region *io;
|
||||
|
||||
vdev = &proc->vdev;
|
||||
ipi = (struct ipi_info *)(vdev->intr_info.data);
|
||||
io = ipi->io;
|
||||
while(1) {
|
||||
unsigned int ipi_intr_status =
|
||||
(unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
|
||||
if (ipi_intr_status & ipi->ipi_chn_mask) {
|
||||
metal_io_write32(io, IPI_ISR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
hil_notified(proc, (uint32_t)(-1));
|
||||
return 0;
|
||||
} else if (nonblock) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
_rproc_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
|
||||
metal_phys_addr_t pa,
|
||||
size_t size,
|
||||
struct metal_device **dev)
|
||||
{
|
||||
(void)proc;
|
||||
(void)pa;
|
||||
(void)size;
|
||||
|
||||
*dev = NULL;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static void _release_shm(struct hil_proc *proc,
|
||||
struct metal_device *dev,
|
||||
struct metal_io_region *io)
|
||||
{
|
||||
(void)proc;
|
||||
(void)io;
|
||||
hil_close_generic_mem_dev(dev);
|
||||
}
|
||||
|
||||
static int _initialize(struct hil_proc *proc)
|
||||
{
|
||||
int ret;
|
||||
struct proc_intr *intr_info;
|
||||
struct ipi_info *ipi;
|
||||
unsigned int ipi_intr_status;
|
||||
|
||||
if (!proc)
|
||||
return -1;
|
||||
|
||||
intr_info = &(proc->vdev.intr_info);
|
||||
ipi = intr_info->data;
|
||||
|
||||
if (ipi && ipi->name && ipi->bus_name) {
|
||||
ret = metal_device_open(ipi->bus_name, ipi->name,
|
||||
&ipi->dev);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
ipi->io = metal_device_io_region(ipi->dev, 0);
|
||||
intr_info->vect_id = (uintptr_t)ipi->dev->irq_info;
|
||||
} else if (ipi->paddr) {
|
||||
ipi->io = metal_allocate_memory(
|
||||
sizeof(struct metal_io_region));
|
||||
if (!ipi->io)
|
||||
goto error;
|
||||
metal_io_init(ipi->io, (void *)ipi->paddr,
|
||||
&ipi->paddr, 0x1000,
|
||||
(unsigned)(-1),
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (ipi->io) {
|
||||
ipi_intr_status = (unsigned int)metal_io_read32(
|
||||
ipi->io, IPI_ISR_OFFSET);
|
||||
if (ipi_intr_status & ipi->ipi_chn_mask)
|
||||
metal_io_write32(ipi->io, IPI_ISR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
atomic_store(&ipi->sync, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
_release(proc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _release(struct hil_proc *proc)
|
||||
{
|
||||
struct proc_intr *intr_info;
|
||||
struct ipi_info *ipi;
|
||||
|
||||
if (!proc)
|
||||
return;
|
||||
intr_info = &(proc->vdev.intr_info);
|
||||
ipi = (struct ipi_info *)(intr_info->data);
|
||||
if (ipi) {
|
||||
if (ipi->io) {
|
||||
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
|
||||
ipi->ipi_chn_mask);
|
||||
if (ipi->dev) {
|
||||
metal_device_close(ipi->dev);
|
||||
ipi->dev = NULL;
|
||||
} else {
|
||||
metal_free_memory(ipi->io);
|
||||
}
|
||||
ipi->io = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user