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
|
Note that a tiny shell module can be exposed to test the ivshmem feature by
|
||||||
enabling :kconfig:option:`CONFIG_IVSHMEM_SHELL`.
|
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
|
API Reference
|
||||||
*************
|
*************
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,9 @@ source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
||||||
config IVSHMEM_DOORBELL
|
config IVSHMEM_DOORBELL
|
||||||
bool "Support interrupt based ivshmem (doorbell version)"
|
bool "Support interrupt based ivshmem (doorbell version)"
|
||||||
depends on PCIE_MSI_X && PCIE_MSI_MULTI_VECTOR
|
|
||||||
help
|
help
|
||||||
This will enable support of ivshmem-doorbell, i.e. the interrupt
|
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
|
config IVSHMEM_MSI_X_VECTORS
|
||||||
int "How many notification vectors should be pre-allocated?"
|
int "How many notification vectors should be pre-allocated?"
|
||||||
|
@ -44,11 +43,12 @@ config IVSHMEM_MSI_X_VECTORS
|
||||||
ivshmem.
|
ivshmem.
|
||||||
|
|
||||||
config IVSHMEM_INT_PRIORITY
|
config IVSHMEM_INT_PRIORITY
|
||||||
int "Interrupt priority"
|
int "MSI-X interrupt priority"
|
||||||
default 2
|
default 2
|
||||||
depends on IVSHMEM_DOORBELL
|
depends on IVSHMEM_DOORBELL
|
||||||
help
|
help
|
||||||
Interrupt priority used for the MSI-X generated interrupts.
|
Interrupt priority used for the MSI-X generated interrupts.
|
||||||
|
INTx interrupt priority is configured in the device tree.
|
||||||
|
|
||||||
config IVSHMEM_SHELL
|
config IVSHMEM_SHELL
|
||||||
bool "IVshmem shell module"
|
bool "IVshmem shell module"
|
||||||
|
@ -59,4 +59,11 @@ config IVSHMEM_SHELL
|
||||||
|
|
||||||
endif # IVSHMEM
|
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
|
endif # VIRTUALIZATION
|
||||||
|
|
|
@ -13,9 +13,30 @@
|
||||||
#include <zephyr/drivers/pcie/msi.h>
|
#include <zephyr/drivers/pcie/msi.h>
|
||||||
#endif
|
#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_REG_BAR_IDX 0
|
||||||
|
#define IVSHMEM_PCIE_MSI_X_BAR_IDX 1
|
||||||
#define IVSHMEM_PCIE_SHMEM_BAR_IDX 2
|
#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 {
|
struct ivshmem_param {
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
struct k_poll_signal *signal;
|
struct k_poll_signal *signal;
|
||||||
|
@ -32,6 +53,14 @@ struct ivshmem {
|
||||||
struct ivshmem_param params[CONFIG_IVSHMEM_MSI_X_VECTORS];
|
struct ivshmem_param params[CONFIG_IVSHMEM_MSI_X_VECTORS];
|
||||||
uint16_t n_vectors;
|
uint16_t n_vectors;
|
||||||
#endif
|
#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 {
|
struct ivshmem_reg {
|
||||||
|
@ -41,6 +70,26 @@ struct ivshmem_reg {
|
||||||
uint32_t doorbell;
|
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))
|
#define IVSHMEM_GEN_DOORBELL(i, v) ((i << 16) | (v & 0xFFFF))
|
||||||
|
|
||||||
#endif /* ZEPHYR_DRIVERS_VIRTUALIZATION_VIRT_IVSHMEM_H_ */
|
#endif /* ZEPHYR_DRIVERS_VIRTUALIZATION_VIRT_IVSHMEM_H_ */
|
||||||
|
|
|
@ -6,3 +6,12 @@ description: ivShMem device properties
|
||||||
compatible: "qemu,ivshmem"
|
compatible: "qemu,ivshmem"
|
||||||
|
|
||||||
include: [base.yaml, pcie-device.yaml]
|
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" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define IVSHMEM_V2_PROTO_UNDEFINED 0x0000
|
||||||
|
#define IVSHMEM_V2_PROTO_NET 0x0001
|
||||||
|
|
||||||
typedef size_t (*ivshmem_get_mem_f)(const struct device *dev,
|
typedef size_t (*ivshmem_get_mem_f)(const struct device *dev,
|
||||||
uintptr_t *memmap);
|
uintptr_t *memmap);
|
||||||
|
|
||||||
|
@ -36,12 +39,45 @@ typedef int (*ivshmem_register_handler_f)(const struct device *dev,
|
||||||
struct k_poll_signal *signal,
|
struct k_poll_signal *signal,
|
||||||
uint16_t vector);
|
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 {
|
__subsystem struct ivshmem_driver_api {
|
||||||
ivshmem_get_mem_f get_mem;
|
ivshmem_get_mem_f get_mem;
|
||||||
ivshmem_get_id_f get_id;
|
ivshmem_get_id_f get_id;
|
||||||
ivshmem_get_vectors_f get_vectors;
|
ivshmem_get_vectors_f get_vectors;
|
||||||
ivshmem_int_peer_f int_peer;
|
ivshmem_int_peer_f int_peer;
|
||||||
ivshmem_register_handler_f register_handler;
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue