drivers: virtualization: Add interface for ivshmem-v2
ivshmem-v2 is primarily used for IPC in the Jailhouse hypervisor Signed-off-by: Grant Ramsay <gramsay@enphaseenergy.com>
This commit is contained in:
parent
b0668cc586
commit
4ed404a27f
5 changed files with 259 additions and 4 deletions
|
@ -38,6 +38,19 @@ vectors that will be needed.
|
|||
Note that a tiny shell module can be exposed to test the ivshmem feature by
|
||||
enabling :kconfig:option:`CONFIG_IVSHMEM_SHELL`.
|
||||
|
||||
ivshmem-v2
|
||||
**********
|
||||
|
||||
Zephyr also supports ivshmem-v2:
|
||||
|
||||
https://github.com/siemens/jailhouse/blob/master/Documentation/ivshmem-v2-specification.md
|
||||
|
||||
This is primarily used for IPC in the Jailhouse hypervisor
|
||||
(e.g. :ref:`eth_ivshmem_sample`). It is also possible to use ivshmem-v2 without
|
||||
Jailhouse by building the Siemens fork of QEMU, and modifying the QEMU launch flags:
|
||||
|
||||
https://github.com/siemens/qemu/tree/wip/ivshmem2
|
||||
|
||||
API Reference
|
||||
*************
|
||||
|
||||
|
|
|
@ -28,10 +28,9 @@ source "subsys/logging/Kconfig.template.log_config"
|
|||
|
||||
config IVSHMEM_DOORBELL
|
||||
bool "Support interrupt based ivshmem (doorbell version)"
|
||||
depends on PCIE_MSI_X && PCIE_MSI_MULTI_VECTOR
|
||||
help
|
||||
This will enable support of ivshmem-doorbell, i.e. the interrupt
|
||||
based ivshmem.
|
||||
based ivshmem. For ivshmem-v2 INTx interrupts are also supported.
|
||||
|
||||
config IVSHMEM_MSI_X_VECTORS
|
||||
int "How many notification vectors should be pre-allocated?"
|
||||
|
@ -44,11 +43,12 @@ config IVSHMEM_MSI_X_VECTORS
|
|||
ivshmem.
|
||||
|
||||
config IVSHMEM_INT_PRIORITY
|
||||
int "Interrupt priority"
|
||||
int "MSI-X interrupt priority"
|
||||
default 2
|
||||
depends on IVSHMEM_DOORBELL
|
||||
help
|
||||
Interrupt priority used for the MSI-X generated interrupts.
|
||||
INTx interrupt priority is configured in the device tree.
|
||||
|
||||
config IVSHMEM_SHELL
|
||||
bool "IVshmem shell module"
|
||||
|
@ -59,4 +59,11 @@ config IVSHMEM_SHELL
|
|||
|
||||
endif # IVSHMEM
|
||||
|
||||
config IVSHMEM_V2
|
||||
bool "Inter-VM shared memory v2 (ivshmem-v2)"
|
||||
select IVSHMEM
|
||||
help
|
||||
Enable ivshmem-v2 support.
|
||||
ivshmem-v2 is primarily used for IPC in the Jailhouse hypervisor.
|
||||
|
||||
endif # VIRTUALIZATION
|
||||
|
|
|
@ -13,9 +13,30 @@
|
|||
#include <zephyr/drivers/pcie/msi.h>
|
||||
#endif
|
||||
|
||||
#define PCIE_CONF_CMDSTAT_INTX_DISABLE 0x0400
|
||||
#define PCIE_CONF_INTR_PIN(x) (((x) >> 8) & 0xFFu)
|
||||
|
||||
#define IVSHMEM_CFG_ID 0x00
|
||||
#define IVSHMEM_CFG_NEXT_CAP 0x01
|
||||
#define IVSHMEM_CFG_LENGTH 0x02
|
||||
#define IVSHMEM_CFG_PRIV_CNTL 0x03
|
||||
#define IVSHMEM_PRIV_CNTL_ONESHOT_INT BIT(0)
|
||||
#define IVSHMEM_CFG_STATE_TAB_SZ 0x04
|
||||
#define IVSHMEM_CFG_RW_SECTION_SZ 0x08
|
||||
#define IVSHMEM_CFG_OUTPUT_SECTION_SZ 0x10
|
||||
#define IVSHMEM_CFG_ADDRESS 0x18
|
||||
|
||||
#define IVSHMEM_INT_ENABLE BIT(0)
|
||||
|
||||
#define IVSHMEM_PCIE_REG_BAR_IDX 0
|
||||
#define IVSHMEM_PCIE_MSI_X_BAR_IDX 1
|
||||
#define IVSHMEM_PCIE_SHMEM_BAR_IDX 2
|
||||
|
||||
#define PCIE_INTX_PIN_MIN 1
|
||||
#define PCIE_INTX_PIN_MAX 4
|
||||
|
||||
#define INTX_IRQ_UNUSED UINT32_MAX
|
||||
|
||||
struct ivshmem_param {
|
||||
const struct device *dev;
|
||||
struct k_poll_signal *signal;
|
||||
|
@ -32,6 +53,14 @@ struct ivshmem {
|
|||
struct ivshmem_param params[CONFIG_IVSHMEM_MSI_X_VECTORS];
|
||||
uint16_t n_vectors;
|
||||
#endif
|
||||
#ifdef CONFIG_IVSHMEM_V2
|
||||
bool ivshmem_v2;
|
||||
uint32_t max_peers;
|
||||
size_t rw_section_size;
|
||||
size_t rw_section_offset;
|
||||
size_t output_section_size;
|
||||
size_t output_section_offset;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ivshmem_reg {
|
||||
|
@ -41,6 +70,26 @@ struct ivshmem_reg {
|
|||
uint32_t doorbell;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IVSHMEM_V2
|
||||
|
||||
struct ivshmem_v2_reg {
|
||||
uint32_t id;
|
||||
uint32_t max_peers;
|
||||
uint32_t int_control;
|
||||
uint32_t doorbell;
|
||||
uint32_t state;
|
||||
};
|
||||
|
||||
struct ivshmem_cfg {
|
||||
struct intx_info {
|
||||
uint32_t irq;
|
||||
uint32_t priority;
|
||||
uint32_t flags;
|
||||
} intx_info[PCIE_INTX_PIN_MAX];
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IVSHMEM_V2 */
|
||||
|
||||
#define IVSHMEM_GEN_DOORBELL(i, v) ((i << 16) | (v & 0xFFFF))
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_VIRTUALIZATION_VIRT_IVSHMEM_H_ */
|
||||
|
|
|
@ -6,3 +6,12 @@ description: ivShMem device properties
|
|||
compatible: "qemu,ivshmem"
|
||||
|
||||
include: [base.yaml, pcie-device.yaml]
|
||||
|
||||
properties:
|
||||
|
||||
ivshmem-v2:
|
||||
type: boolean
|
||||
description: |
|
||||
Use ivshmem-v2.
|
||||
Primarily used for IPC in the Jailhouse hypervisor.
|
||||
ivshmem-v2 is not compatible with v1.
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IVSHMEM_V2_PROTO_UNDEFINED 0x0000
|
||||
#define IVSHMEM_V2_PROTO_NET 0x0001
|
||||
|
||||
typedef size_t (*ivshmem_get_mem_f)(const struct device *dev,
|
||||
uintptr_t *memmap);
|
||||
|
||||
|
@ -36,12 +39,45 @@ typedef int (*ivshmem_register_handler_f)(const struct device *dev,
|
|||
struct k_poll_signal *signal,
|
||||
uint16_t vector);
|
||||
|
||||
#ifdef CONFIG_IVSHMEM_V2
|
||||
|
||||
typedef size_t (*ivshmem_get_rw_mem_section_f)(const struct device *dev,
|
||||
uintptr_t *memmap);
|
||||
|
||||
typedef size_t (*ivshmem_get_output_mem_section_f)(const struct device *dev,
|
||||
uint32_t peer_id,
|
||||
uintptr_t *memmap);
|
||||
|
||||
typedef uint32_t (*ivshmem_get_state_f)(const struct device *dev,
|
||||
uint32_t peer_id);
|
||||
|
||||
typedef int (*ivshmem_set_state_f)(const struct device *dev,
|
||||
uint32_t state);
|
||||
|
||||
typedef uint32_t (*ivshmem_get_max_peers_f)(const struct device *dev);
|
||||
|
||||
typedef uint16_t (*ivshmem_get_protocol_f)(const struct device *dev);
|
||||
|
||||
typedef int (*ivshmem_enable_interrupts_f)(const struct device *dev,
|
||||
bool enable);
|
||||
|
||||
#endif /* CONFIG_IVSHMEM_V2 */
|
||||
|
||||
__subsystem struct ivshmem_driver_api {
|
||||
ivshmem_get_mem_f get_mem;
|
||||
ivshmem_get_id_f get_id;
|
||||
ivshmem_get_vectors_f get_vectors;
|
||||
ivshmem_int_peer_f int_peer;
|
||||
ivshmem_register_handler_f register_handler;
|
||||
#ifdef CONFIG_IVSHMEM_V2
|
||||
ivshmem_get_rw_mem_section_f get_rw_mem_section;
|
||||
ivshmem_get_output_mem_section_f get_output_mem_section;
|
||||
ivshmem_get_state_f get_state;
|
||||
ivshmem_set_state_f set_state;
|
||||
ivshmem_get_max_peers_f get_max_peers;
|
||||
ivshmem_get_protocol_f get_protocol;
|
||||
ivshmem_enable_interrupts_f enable_interrupts;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -148,6 +184,147 @@ static inline int z_impl_ivshmem_register_handler(const struct device *dev,
|
|||
return api->register_handler(dev, signal, vector);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IVSHMEM_V2
|
||||
|
||||
/**
|
||||
* @brief Get the ivshmem read/write section (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param memmap A pointer to fill in with the memory address
|
||||
*
|
||||
* @return the size of the memory mapped, or 0
|
||||
*/
|
||||
__syscall size_t ivshmem_get_rw_mem_section(const struct device *dev,
|
||||
uintptr_t *memmap);
|
||||
|
||||
static inline size_t z_impl_ivshmem_get_rw_mem_section(const struct device *dev,
|
||||
uintptr_t *memmap)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->get_rw_mem_section(dev, memmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the ivshmem output section for a peer (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param peer_id The VM ID whose output memory section to get
|
||||
* @param memmap A pointer to fill in with the memory address
|
||||
*
|
||||
* @return the size of the memory mapped, or 0
|
||||
*/
|
||||
__syscall size_t ivshmem_get_output_mem_section(const struct device *dev,
|
||||
uint32_t peer_id,
|
||||
uintptr_t *memmap);
|
||||
|
||||
static inline size_t z_impl_ivshmem_get_output_mem_section(const struct device *dev,
|
||||
uint32_t peer_id,
|
||||
uintptr_t *memmap)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->get_output_mem_section(dev, peer_id, memmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the state value of a peer (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param peer_id The VM ID whose state to get
|
||||
*
|
||||
* @return the state value of the peer
|
||||
*/
|
||||
__syscall uint32_t ivshmem_get_state(const struct device *dev,
|
||||
uint32_t peer_id);
|
||||
|
||||
static inline uint32_t z_impl_ivshmem_get_state(const struct device *dev,
|
||||
uint32_t peer_id)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->get_state(dev, peer_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set our state (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param state The state value to set
|
||||
*
|
||||
* @return 0 on success, a negative errno otherwise
|
||||
*/
|
||||
__syscall int ivshmem_set_state(const struct device *dev,
|
||||
uint32_t state);
|
||||
|
||||
static inline int z_impl_ivshmem_set_state(const struct device *dev,
|
||||
uint32_t state)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->set_state(dev, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the maximum number of peers supported (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
*
|
||||
* @return the maximum number of peers supported, or 0
|
||||
*/
|
||||
__syscall uint32_t ivshmem_get_max_peers(const struct device *dev);
|
||||
|
||||
static inline uint32_t z_impl_ivshmem_get_max_peers(const struct device *dev)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->get_max_peers(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the protocol used by this ivshmem instance (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
*
|
||||
* @return the protocol
|
||||
*/
|
||||
__syscall uint16_t ivshmem_get_protocol(const struct device *dev);
|
||||
|
||||
static inline uint16_t z_impl_ivshmem_get_protocol(const struct device *dev)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->get_protocol(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt enablement for our VM (ivshmem-v2 only)
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance
|
||||
* @param enable True to enable interrupts, false to disable
|
||||
*
|
||||
* @return 0 on success, a negative errno otherwise
|
||||
*/
|
||||
__syscall int ivshmem_enable_interrupts(const struct device *dev,
|
||||
bool enable);
|
||||
|
||||
static inline int z_impl_ivshmem_enable_interrupts(const struct device *dev,
|
||||
bool enable)
|
||||
{
|
||||
const struct ivshmem_driver_api *api =
|
||||
(const struct ivshmem_driver_api *)dev->api;
|
||||
|
||||
return api->enable_interrupts(dev, enable);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IVSHMEM_V2 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue