mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-01 07:36:47 +07:00
265 lines
9.0 KiB
C
265 lines
9.0 KiB
C
|
/*
|
||
|
* Remote Processor Framework
|
||
|
*
|
||
|
* Copyright(c) 2011 Texas Instruments, Inc.
|
||
|
* Copyright(c) 2011 Google, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in
|
||
|
* the documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
* * Neither the name Texas Instruments nor the names of its
|
||
|
* contributors may be used to endorse or promote products derived
|
||
|
* from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#ifndef REMOTEPROC_H
|
||
|
#define REMOTEPROC_H
|
||
|
|
||
|
#include <linux/types.h>
|
||
|
#include <linux/kref.h>
|
||
|
#include <linux/klist.h>
|
||
|
#include <linux/mutex.h>
|
||
|
#include <linux/virtio.h>
|
||
|
#include <linux/completion.h>
|
||
|
|
||
|
/*
|
||
|
* The alignment between the consumer and producer parts of the vring.
|
||
|
* Note: this is part of the "wire" protocol. If you change this, you need
|
||
|
* to update your peers too.
|
||
|
*/
|
||
|
#define AMP_VRING_ALIGN (4096)
|
||
|
|
||
|
/**
|
||
|
* struct fw_resource - describes an entry from the resource section
|
||
|
* @type: resource type
|
||
|
* @id: index number of the resource
|
||
|
* @da: device address of the resource
|
||
|
* @pa: physical address of the resource
|
||
|
* @len: size, in bytes, of the resource
|
||
|
* @flags: properties of the resource, e.g. iommu protection required
|
||
|
* @reserved: must be 0 atm
|
||
|
* @name: name of resource
|
||
|
*
|
||
|
* The remote processor firmware should contain a "resource table":
|
||
|
* array of 'struct fw_resource' entries.
|
||
|
*
|
||
|
* Some resources entries are mere announcements, where the host is informed
|
||
|
* of specific remoteproc configuration. Other entries require the host to
|
||
|
* do something (e.g. reserve a requested resource) and possibly also reply
|
||
|
* by overwriting a member inside 'struct fw_resource' with info about the
|
||
|
* allocated resource.
|
||
|
*
|
||
|
* Different resource entries use different members of this struct,
|
||
|
* with different meanings. This is pretty limiting and error-prone,
|
||
|
* so the plan is to move to variable-length TLV-based resource entries,
|
||
|
* where each resource type will have its own structure.
|
||
|
*/
|
||
|
struct fw_resource {
|
||
|
u32 type;
|
||
|
u32 id;
|
||
|
u64 da;
|
||
|
u64 pa;
|
||
|
u32 len;
|
||
|
u32 flags;
|
||
|
u8 reserved[16];
|
||
|
u8 name[48];
|
||
|
} __packed;
|
||
|
|
||
|
/**
|
||
|
* enum fw_resource_type - types of resource entries
|
||
|
*
|
||
|
* @RSC_CARVEOUT: request for allocation of a physically contiguous
|
||
|
* memory region.
|
||
|
* @RSC_DEVMEM: request to iommu_map a memory-based peripheral.
|
||
|
* @RSC_TRACE: announces the availability of a trace buffer into which
|
||
|
* the remote processor will be writing logs. In this case,
|
||
|
* 'da' indicates the device address where logs are written to,
|
||
|
* and 'len' is the size of the trace buffer.
|
||
|
* @RSC_VRING: request for allocation of a virtio vring (address should
|
||
|
* be indicated in 'da', and 'len' should contain the number
|
||
|
* of buffers supported by the vring).
|
||
|
* @RSC_VIRTIO_DEV: this entry declares about support for a virtio device,
|
||
|
* and serves as the virtio header. 'da' holds the
|
||
|
* the virtio device features, 'pa' holds the virtio guest
|
||
|
* features, 'len' holds the virtio status, and 'flags' holds
|
||
|
* the virtio id (currently only VIRTIO_ID_RPMSG is supported).
|
||
|
*
|
||
|
* Most of the resource entries share the basic idea of address/length
|
||
|
* negotiation with the host: the firmware usually asks (on behalf of the
|
||
|
* remote processor that will soon be booted with it) for memory
|
||
|
* of size 'len' bytes, and the host needs to allocate it and provide
|
||
|
* the device/physical address (when relevant) in 'da'/'pa' respectively.
|
||
|
*
|
||
|
* If the firmware is compiled with hard coded device addresses, and
|
||
|
* can't handle dynamically allocated 'da' values, then the 'da' field
|
||
|
* will contain the expected device addresses (today we actually only support
|
||
|
* this scheme, as there aren't yet any use cases for dynamically allocated
|
||
|
* device addresses).
|
||
|
*/
|
||
|
enum fw_resource_type {
|
||
|
RSC_CARVEOUT = 0,
|
||
|
RSC_DEVMEM = 1,
|
||
|
RSC_TRACE = 2,
|
||
|
RSC_VRING = 3,
|
||
|
RSC_VIRTIO_DEV = 4,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* struct rproc_mem_entry - memory entry descriptor
|
||
|
* @va: virtual address
|
||
|
* @dma: dma address
|
||
|
* @len: length, in bytes
|
||
|
* @da: device address
|
||
|
* @priv: associated data
|
||
|
* @node: list node
|
||
|
*/
|
||
|
struct rproc_mem_entry {
|
||
|
void *va;
|
||
|
dma_addr_t dma;
|
||
|
int len;
|
||
|
u64 da;
|
||
|
void *priv;
|
||
|
struct list_head node;
|
||
|
};
|
||
|
|
||
|
struct rproc;
|
||
|
|
||
|
/**
|
||
|
* struct rproc_ops - platform-specific device handlers
|
||
|
* @start: power on the device and boot it
|
||
|
* @stop: power off the device
|
||
|
* @kick: kick a virtqueue (virtqueue id given as a parameter)
|
||
|
*/
|
||
|
struct rproc_ops {
|
||
|
int (*start)(struct rproc *rproc);
|
||
|
int (*stop)(struct rproc *rproc);
|
||
|
void (*kick)(struct rproc *rproc, int vqid);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* enum rproc_state - remote processor states
|
||
|
* @RPROC_OFFLINE: device is powered off
|
||
|
* @RPROC_SUSPENDED: device is suspended; needs to be woken up to receive
|
||
|
* a message.
|
||
|
* @RPROC_RUNNING: device is up and running
|
||
|
* @RPROC_CRASHED: device has crashed; need to start recovery
|
||
|
* @RPROC_LAST: just keep this one at the end
|
||
|
*
|
||
|
* Please note that the values of these states are used as indices
|
||
|
* to rproc_state_string, a state-to-name lookup table,
|
||
|
* so please keep the two synchronized. @RPROC_LAST is used to check
|
||
|
* the validity of an index before the lookup table is accessed, so
|
||
|
* please update it as needed too.
|
||
|
*/
|
||
|
enum rproc_state {
|
||
|
RPROC_OFFLINE = 0,
|
||
|
RPROC_SUSPENDED = 1,
|
||
|
RPROC_RUNNING = 2,
|
||
|
RPROC_CRASHED = 3,
|
||
|
RPROC_LAST = 4,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* struct rproc - represents a physical remote processor device
|
||
|
* @node: klist node of this rproc object
|
||
|
* @domain: iommu domain
|
||
|
* @name: human readable name of the rproc
|
||
|
* @firmware: name of firmware file to be loaded
|
||
|
* @priv: private data which belongs to the platform-specific rproc module
|
||
|
* @ops: platform-specific start/stop rproc handlers
|
||
|
* @dev: underlying device
|
||
|
* @refcount: refcount of users that have a valid pointer to this rproc
|
||
|
* @power: refcount of users who need this rproc powered up
|
||
|
* @state: state of the device
|
||
|
* @lock: lock which protects concurrent manipulations of the rproc
|
||
|
* @dbg_dir: debugfs directory of this rproc device
|
||
|
* @traces: list of trace buffers
|
||
|
* @num_traces: number of trace buffers
|
||
|
* @carveouts: list of physically contiguous memory allocations
|
||
|
* @mappings: list of iommu mappings we initiated, needed on shutdown
|
||
|
* @firmware_loading_complete: marks e/o asynchronous firmware loading
|
||
|
* @bootaddr: address of first instruction to boot rproc with (optional)
|
||
|
* @rvdev: virtio device (we only support a single rpmsg virtio device for now)
|
||
|
*/
|
||
|
struct rproc {
|
||
|
struct klist_node node;
|
||
|
struct iommu_domain *domain;
|
||
|
const char *name;
|
||
|
const char *firmware;
|
||
|
void *priv;
|
||
|
const struct rproc_ops *ops;
|
||
|
struct device *dev;
|
||
|
struct kref refcount;
|
||
|
atomic_t power;
|
||
|
unsigned int state;
|
||
|
struct mutex lock;
|
||
|
struct dentry *dbg_dir;
|
||
|
struct list_head traces;
|
||
|
int num_traces;
|
||
|
struct list_head carveouts;
|
||
|
struct list_head mappings;
|
||
|
struct completion firmware_loading_complete;
|
||
|
u64 bootaddr;
|
||
|
struct rproc_vdev *rvdev;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* struct rproc_vdev - remoteproc state for a supported virtio device
|
||
|
* @rproc: the rproc handle
|
||
|
* @vdev: the virio device
|
||
|
* @vq: the virtqueues for this vdev
|
||
|
* @vring: the vrings for this vdev
|
||
|
* @dfeatures: virtio device features
|
||
|
* @gfeatures: virtio guest features
|
||
|
*/
|
||
|
struct rproc_vdev {
|
||
|
struct rproc *rproc;
|
||
|
struct virtio_device vdev;
|
||
|
struct virtqueue *vq[2];
|
||
|
struct rproc_mem_entry vring[2];
|
||
|
unsigned long dfeatures;
|
||
|
unsigned long gfeatures;
|
||
|
};
|
||
|
|
||
|
struct rproc *rproc_get_by_name(const char *name);
|
||
|
void rproc_put(struct rproc *rproc);
|
||
|
|
||
|
struct rproc *rproc_alloc(struct device *dev, const char *name,
|
||
|
const struct rproc_ops *ops,
|
||
|
const char *firmware, int len);
|
||
|
void rproc_free(struct rproc *rproc);
|
||
|
int rproc_register(struct rproc *rproc);
|
||
|
int rproc_unregister(struct rproc *rproc);
|
||
|
|
||
|
int rproc_boot(struct rproc *rproc);
|
||
|
void rproc_shutdown(struct rproc *rproc);
|
||
|
|
||
|
static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
|
||
|
{
|
||
|
struct rproc_vdev *rvdev = container_of(vdev, struct rproc_vdev, vdev);
|
||
|
|
||
|
return rvdev->rproc;
|
||
|
}
|
||
|
|
||
|
#endif /* REMOTEPROC_H */
|