224 lines
5.3 KiB
C
224 lines
5.3 KiB
C
/*
|
|
* Copyright (c) 2014, Mentor Graphics Corporation
|
|
* Copyright (c) 2018, Xilinx Inc.
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <metal/io.h>
|
|
#include <openamp/rsc_table_parser.h>
|
|
|
|
static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc);
|
|
|
|
/* Resources handler */
|
|
rsc_handler rsc_handler_table[] = {
|
|
handle_carve_out_rsc, /**< carved out resource */
|
|
handle_dummy_rsc, /**< IOMMU dev mem resource */
|
|
handle_trace_rsc, /**< trace buffer resource */
|
|
handle_vdev_rsc, /**< virtio resource */
|
|
handle_dummy_rsc, /**< rproc shared memory resource */
|
|
handle_dummy_rsc, /**< firmware checksum resource */
|
|
};
|
|
|
|
int handle_rsc_table(struct remoteproc *rproc,
|
|
struct resource_table *rsc_table, int size,
|
|
struct metal_io_region *io)
|
|
{
|
|
char *rsc_start;
|
|
unsigned int rsc_type;
|
|
unsigned int idx, offset;
|
|
int status = 0;
|
|
|
|
/* Validate rsc table header fields */
|
|
|
|
/* Minimum rsc table size */
|
|
if (sizeof(struct resource_table) > (unsigned int)size) {
|
|
return -RPROC_ERR_RSC_TAB_TRUNC;
|
|
}
|
|
|
|
/* Supported version */
|
|
if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) {
|
|
return -RPROC_ERR_RSC_TAB_VER;
|
|
}
|
|
|
|
/* Offset array */
|
|
offset = sizeof(struct resource_table)
|
|
+ rsc_table->num * sizeof(rsc_table->offset[0]);
|
|
|
|
if (offset > (unsigned int)size) {
|
|
return -RPROC_ERR_RSC_TAB_TRUNC;
|
|
}
|
|
|
|
/* Reserved fields - must be zero */
|
|
if ((rsc_table->reserved[0] != 0 || rsc_table->reserved[1]) != 0) {
|
|
return -RPROC_ERR_RSC_TAB_RSVD;
|
|
}
|
|
|
|
/* Loop through the offset array and parse each resource entry */
|
|
for (idx = 0; idx < rsc_table->num; idx++) {
|
|
rsc_start = (char *)rsc_table;
|
|
rsc_start += rsc_table->offset[idx];
|
|
if (io &&
|
|
metal_io_virt_to_offset(io, rsc_start) == METAL_BAD_OFFSET)
|
|
return -RPROC_ERR_RSC_TAB_TRUNC;
|
|
rsc_type = *((uint32_t *)rsc_start);
|
|
if (rsc_type < RSC_LAST)
|
|
status = rsc_handler_table[rsc_type](rproc,
|
|
rsc_start);
|
|
else if (rsc_type >= RSC_VENDOR_START &&
|
|
rsc_type <= RSC_VENDOR_END)
|
|
status = handle_vendor_rsc(rproc, rsc_start);
|
|
if (status == -RPROC_ERR_RSC_TAB_NS) {
|
|
status = 0;
|
|
continue;
|
|
}
|
|
else if (status)
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* handle_carve_out_rsc
|
|
*
|
|
* Carveout resource handler.
|
|
*
|
|
* @param rproc - pointer to remote remoteproc
|
|
* @param rsc - pointer to carveout resource
|
|
*
|
|
* @returns - 0 for success, or negative value for failure
|
|
*
|
|
*/
|
|
int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc)
|
|
{
|
|
struct fw_rsc_carveout *carve_rsc = (struct fw_rsc_carveout *)rsc;
|
|
metal_phys_addr_t da;
|
|
metal_phys_addr_t pa;
|
|
size_t size;
|
|
unsigned int attribute;
|
|
|
|
/* Validate resource fields */
|
|
if (!carve_rsc) {
|
|
return -RPROC_ERR_RSC_TAB_NP;
|
|
}
|
|
|
|
if (carve_rsc->reserved) {
|
|
return -RPROC_ERR_RSC_TAB_RSVD;
|
|
}
|
|
pa = carve_rsc->pa;
|
|
da = carve_rsc->da;
|
|
size = carve_rsc->len;
|
|
attribute = carve_rsc->flags;
|
|
if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL))
|
|
return 0;
|
|
else
|
|
return -RPROC_EINVAL;
|
|
}
|
|
|
|
int handle_vendor_rsc(struct remoteproc *rproc, void *rsc)
|
|
{
|
|
if (rproc && rproc->ops->handle_rsc) {
|
|
struct fw_rsc_vendor *vend_rsc = rsc;
|
|
size_t len = vend_rsc->len;
|
|
|
|
return rproc->ops->handle_rsc(rproc, rsc, len);
|
|
}
|
|
return -RPROC_ERR_RSC_TAB_NS;
|
|
}
|
|
|
|
int handle_vdev_rsc(struct remoteproc *rproc, void *rsc)
|
|
{
|
|
struct fw_rsc_vdev *vdev_rsc = (struct fw_rsc_vdev *)rsc;
|
|
unsigned int notifyid, i, num_vrings;
|
|
|
|
/* only assign notification IDs but do not initialize vdev */
|
|
notifyid = vdev_rsc->notifyid;
|
|
if (notifyid == RSC_NOTIFY_ID_ANY) {
|
|
notifyid = remoteproc_allocate_id(rproc,
|
|
notifyid, notifyid + 1);
|
|
vdev_rsc->notifyid = notifyid;
|
|
}
|
|
|
|
num_vrings = vdev_rsc->num_of_vrings;
|
|
for (i = 0; i < num_vrings; i++) {
|
|
struct fw_rsc_vdev_vring *vring_rsc;
|
|
|
|
vring_rsc = &vdev_rsc->vring[i];
|
|
notifyid = vring_rsc->notifyid;
|
|
if (notifyid == RSC_NOTIFY_ID_ANY) {
|
|
notifyid = remoteproc_allocate_id(rproc,
|
|
notifyid,
|
|
notifyid + 1);
|
|
vdev_rsc->notifyid = notifyid;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* handle_trace_rsc
|
|
*
|
|
* trace resource handler.
|
|
*
|
|
* @param rproc - pointer to remote remoteproc
|
|
* @param rsc - pointer to trace resource
|
|
*
|
|
* @returns - no service error
|
|
*
|
|
*/
|
|
int handle_trace_rsc(struct remoteproc *rproc, void *rsc)
|
|
{
|
|
struct fw_rsc_trace *vdev_rsc = (struct fw_rsc_trace *)rsc;
|
|
(void)rproc;
|
|
|
|
if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0)
|
|
return 0;
|
|
/* FIXME: master should allocated a memory used by slave */
|
|
|
|
return -RPROC_ERR_RSC_TAB_NS;
|
|
}
|
|
|
|
/**
|
|
* handle_dummy_rsc
|
|
*
|
|
* dummy resource handler.
|
|
*
|
|
* @param rproc - pointer to remote remoteproc
|
|
* @param rsc - pointer to trace resource
|
|
*
|
|
* @returns - no service error
|
|
*
|
|
*/
|
|
static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc)
|
|
{
|
|
(void)rproc;
|
|
(void)rsc;
|
|
|
|
return -RPROC_ERR_RSC_TAB_NS;
|
|
}
|
|
|
|
size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index)
|
|
{
|
|
struct resource_table *r_table = rsc_table;
|
|
unsigned int i, rsc_index;
|
|
unsigned int lrsc_type;
|
|
char *rsc_start;
|
|
|
|
metal_assert(r_table);
|
|
/* Loop through the offset array and parse each resource entry */
|
|
rsc_index = 0;
|
|
for (i = 0; i < r_table->num; i++) {
|
|
rsc_start = (char *)r_table;
|
|
rsc_start += r_table->offset[i];
|
|
lrsc_type = *((uint32_t *)rsc_start);
|
|
if (lrsc_type == rsc_type) {
|
|
if (rsc_index++ == index)
|
|
return r_table->offset[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|