mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
virtio,pc,pci: features, fixes
virtio sound card support vhost-user: back-end state migration cxl: line length reduction enabling fabric management vhost-vdpa: shadow virtqueue hash calculation Support shadow virtqueue RSS Support tests: CPU topology related smbios test cases Fixes, cleanups all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmVKDDoPHG1zdEByZWRo YXQuY29tAAoJECgfDbjSjVRpF08H/0Zts8uvkHbgiOEJw4JMHU6/VaCipfIYsp01 GSfwYOyEsXJ7GIxKWaCiMnWXEm7tebNCPKf3DoUtcAojQj3vuF9XbWBKw/bfRn83 nGO/iiwbYViSKxkwqUI+Up5YiN9o0M8gBFrY0kScPezbnYmo5u2bcADdEEq6gH68 D0Ea8i+WmszL891ypvgCDBL2ObDk3qX3vA5Q6J2I+HKX2ofJM59BwaKwS5ghw+IG BmbKXUZJNjUQfN9dQ7vJuiuqdknJ2xUzwW2Vn612ffarbOZB1DZ6ruWlrHty5TjX 0w4IXEJPBgZYbX9oc6zvTQnbLDBJbDU89mnme0TcmNMKWmQKTtc= =vEv+ -----END PGP SIGNATURE----- Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging virtio,pc,pci: features, fixes virtio sound card support vhost-user: back-end state migration cxl: line length reduction enabling fabric management vhost-vdpa: shadow virtqueue hash calculation Support shadow virtqueue RSS Support tests: CPU topology related smbios test cases Fixes, cleanups all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmVKDDoPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRpF08H/0Zts8uvkHbgiOEJw4JMHU6/VaCipfIYsp01 # GSfwYOyEsXJ7GIxKWaCiMnWXEm7tebNCPKf3DoUtcAojQj3vuF9XbWBKw/bfRn83 # nGO/iiwbYViSKxkwqUI+Up5YiN9o0M8gBFrY0kScPezbnYmo5u2bcADdEEq6gH68 # D0Ea8i+WmszL891ypvgCDBL2ObDk3qX3vA5Q6J2I+HKX2ofJM59BwaKwS5ghw+IG # BmbKXUZJNjUQfN9dQ7vJuiuqdknJ2xUzwW2Vn612ffarbOZB1DZ6ruWlrHty5TjX # 0w4IXEJPBgZYbX9oc6zvTQnbLDBJbDU89mnme0TcmNMKWmQKTtc= # =vEv+ # -----END PGP SIGNATURE----- # gpg: Signature made Tue 07 Nov 2023 18:06:50 HKT # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (63 commits) acpi/tests/avocado/bits: enable console logging from bits VM acpi/tests/avocado/bits: enforce 32-bit SMBIOS entry point hw/cxl: Add tunneled command support to mailbox for switch cci. hw/cxl: Add dummy security state get hw/cxl/type3: Cleanup multiple CXL_TYPE3() calls in read/write functions hw/cxl/mbox: Add Get Background Operation Status Command hw/cxl: Add support for device sanitation hw/cxl/mbox: Wire up interrupts for background completion hw/cxl/mbox: Add support for background operations hw/cxl: Implement Physical Ports status retrieval hw/pci-bridge/cxl_downstream: Set default link width and link speed hw/cxl/mbox: Add Physical Switch Identify command. hw/cxl/mbox: Add Information and Status / Identify command hw/cxl: Add a switch mailbox CCI function hw/pci-bridge/cxl_upstream: Move defintion of device to header. hw/cxl/mbox: Generalize the CCI command processing hw/cxl/mbox: Pull the CCI definition out of the CXLDeviceState hw/cxl/mbox: Split mailbox command payload into separate input and output hw/cxl/mbox: Pull the payload out of struct cxl_cmd and make instances constant hw/cxl: Fix a QEMU_BUILD_BUG_ON() in switch statement scope issue. ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
f6b615b52d
53 changed files with 4477 additions and 324 deletions
235
include/hw/audio/virtio-snd.h
Normal file
235
include/hw/audio/virtio-snd.h
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* VIRTIO Sound Device conforming to
|
||||
*
|
||||
* "Virtual I/O Device (VIRTIO) Version 1.2
|
||||
* Committee Specification Draft 01
|
||||
* 09 May 2022"
|
||||
*
|
||||
* Copyright (c) 2023 Emmanouil Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
* Copyright (C) 2019 OpenSynergy GmbH
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_VIRTIO_SOUND_H
|
||||
#define QEMU_VIRTIO_SOUND_H
|
||||
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "audio/audio.h"
|
||||
#include "standard-headers/linux/virtio_ids.h"
|
||||
#include "standard-headers/linux/virtio_snd.h"
|
||||
|
||||
#define TYPE_VIRTIO_SND "virtio-sound-device"
|
||||
#define VIRTIO_SND(obj) \
|
||||
OBJECT_CHECK(VirtIOSound, (obj), TYPE_VIRTIO_SND)
|
||||
|
||||
/* CONFIGURATION SPACE */
|
||||
|
||||
typedef struct virtio_snd_config virtio_snd_config;
|
||||
|
||||
/* COMMON DEFINITIONS */
|
||||
|
||||
/* common header for request/response*/
|
||||
typedef struct virtio_snd_hdr virtio_snd_hdr;
|
||||
|
||||
/* event notification */
|
||||
typedef struct virtio_snd_event virtio_snd_event;
|
||||
|
||||
/* common control request to query an item information */
|
||||
typedef struct virtio_snd_query_info virtio_snd_query_info;
|
||||
|
||||
/* JACK CONTROL MESSAGES */
|
||||
|
||||
typedef struct virtio_snd_jack_hdr virtio_snd_jack_hdr;
|
||||
|
||||
/* jack information structure */
|
||||
typedef struct virtio_snd_jack_info virtio_snd_jack_info;
|
||||
|
||||
/* jack remapping control request */
|
||||
typedef struct virtio_snd_jack_remap virtio_snd_jack_remap;
|
||||
|
||||
/*
|
||||
* PCM CONTROL MESSAGES
|
||||
*/
|
||||
typedef struct virtio_snd_pcm_hdr virtio_snd_pcm_hdr;
|
||||
|
||||
/* PCM stream info structure */
|
||||
typedef struct virtio_snd_pcm_info virtio_snd_pcm_info;
|
||||
|
||||
/* set PCM stream params */
|
||||
typedef struct virtio_snd_pcm_set_params virtio_snd_pcm_set_params;
|
||||
|
||||
/* I/O request header */
|
||||
typedef struct virtio_snd_pcm_xfer virtio_snd_pcm_xfer;
|
||||
|
||||
/* I/O request status */
|
||||
typedef struct virtio_snd_pcm_status virtio_snd_pcm_status;
|
||||
|
||||
/* device structs */
|
||||
|
||||
typedef struct VirtIOSound VirtIOSound;
|
||||
|
||||
typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
|
||||
|
||||
typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
|
||||
|
||||
typedef struct VirtIOSoundPCM VirtIOSoundPCM;
|
||||
|
||||
typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
|
||||
|
||||
/*
|
||||
* The VirtIO sound spec reuses layouts and values from the High Definition
|
||||
* Audio spec (virtio/v1.2: 5.14 Sound Device). This struct handles each I/O
|
||||
* message's buffer (virtio/v1.2: 5.14.6.8 PCM I/O Messages).
|
||||
*
|
||||
* In the case of TX (i.e. playback) buffers, we defer reading the raw PCM data
|
||||
* from the virtqueue until QEMU's sound backsystem calls the output callback.
|
||||
* This is tracked by the `bool populated;` field, which is set to true when
|
||||
* data has been read into our own buffer for consumption.
|
||||
*
|
||||
* VirtIOSoundPCMBuffer has a dynamic size since it includes the raw PCM data
|
||||
* in its allocation. It must be initialized and destroyed as follows:
|
||||
*
|
||||
* size_t size = [[derived from owned VQ element descriptor sizes]];
|
||||
* buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
|
||||
* buffer->elem = [[owned VQ element]];
|
||||
*
|
||||
* [..]
|
||||
*
|
||||
* g_free(buffer->elem);
|
||||
* g_free(buffer);
|
||||
*/
|
||||
struct VirtIOSoundPCMBuffer {
|
||||
QSIMPLEQ_ENTRY(VirtIOSoundPCMBuffer) entry;
|
||||
VirtQueueElement *elem;
|
||||
VirtQueue *vq;
|
||||
size_t size;
|
||||
/*
|
||||
* In TX / Plaback, `offset` represents the first unused position inside
|
||||
* `data`. If `offset == size` then there are no unused data left.
|
||||
*/
|
||||
uint64_t offset;
|
||||
/* Used for the TX queue for lazy I/O copy from `elem` */
|
||||
bool populated;
|
||||
/*
|
||||
* VirtIOSoundPCMBuffer is an unsized type because it ends with an array of
|
||||
* bytes. The size of `data` is determined from the I/O message's read-only
|
||||
* or write-only size when allocating VirtIOSoundPCMBuffer.
|
||||
*/
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
struct VirtIOSoundPCM {
|
||||
VirtIOSound *snd;
|
||||
/*
|
||||
* PCM parameters are a separate field instead of a VirtIOSoundPCMStream
|
||||
* field, because the operation of PCM control requests is first
|
||||
* VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
|
||||
* means that some times we get parameters without having an allocated
|
||||
* stream yet.
|
||||
*/
|
||||
virtio_snd_pcm_set_params *pcm_params;
|
||||
VirtIOSoundPCMStream **streams;
|
||||
};
|
||||
|
||||
struct VirtIOSoundPCMStream {
|
||||
VirtIOSoundPCM *pcm;
|
||||
virtio_snd_pcm_info info;
|
||||
virtio_snd_pcm_set_params params;
|
||||
uint32_t id;
|
||||
/* channel position values (VIRTIO_SND_CHMAP_XXX) */
|
||||
uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
|
||||
VirtIOSound *s;
|
||||
bool flushing;
|
||||
audsettings as;
|
||||
union {
|
||||
SWVoiceIn *in;
|
||||
SWVoiceOut *out;
|
||||
} voice;
|
||||
QemuMutex queue_mutex;
|
||||
bool active;
|
||||
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
|
||||
QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid;
|
||||
};
|
||||
|
||||
/*
|
||||
* PCM stream state machine.
|
||||
* -------------------------
|
||||
*
|
||||
* 5.14.6.6.1 PCM Command Lifecycle
|
||||
* ================================
|
||||
*
|
||||
* A PCM stream has the following command lifecycle:
|
||||
* - `SET PARAMETERS`
|
||||
* The driver negotiates the stream parameters (format, transport, etc) with
|
||||
* the device.
|
||||
* Possible valid transitions: `SET PARAMETERS`, `PREPARE`.
|
||||
* - `PREPARE`
|
||||
* The device prepares the stream (allocates resources, etc).
|
||||
* Possible valid transitions: `SET PARAMETERS`, `PREPARE`, `START`,
|
||||
* `RELEASE`. Output only: the driver transfers data for pre-buffing.
|
||||
* - `START`
|
||||
* The device starts the stream (unmute, putting into running state, etc).
|
||||
* Possible valid transitions: `STOP`.
|
||||
* The driver transfers data to/from the stream.
|
||||
* - `STOP`
|
||||
* The device stops the stream (mute, putting into non-running state, etc).
|
||||
* Possible valid transitions: `START`, `RELEASE`.
|
||||
* - `RELEASE`
|
||||
* The device releases the stream (frees resources, etc).
|
||||
* Possible valid transitions: `SET PARAMETERS`, `PREPARE`.
|
||||
*
|
||||
* +---------------+ +---------+ +---------+ +-------+ +-------+
|
||||
* | SetParameters | | Prepare | | Release | | Start | | Stop |
|
||||
* +---------------+ +---------+ +---------+ +-------+ +-------+
|
||||
* |- | | | |
|
||||
* || | | | |
|
||||
* |< | | | |
|
||||
* |------------->| | | |
|
||||
* |<-------------| | | |
|
||||
* | |- | | |
|
||||
* | || | | |
|
||||
* | |< | | |
|
||||
* | |--------------------->| |
|
||||
* | |---------->| | |
|
||||
* | | | |-------->|
|
||||
* | | | |<--------|
|
||||
* | | |<-------------------|
|
||||
* |<-------------------------| | |
|
||||
* | |<----------| | |
|
||||
*
|
||||
* CTRL in the VirtIOSound device
|
||||
* ==============================
|
||||
*
|
||||
* The control messages that affect the state of a stream arrive in the
|
||||
* `virtio_snd_handle_ctrl()` queue callback and are of type `struct
|
||||
* virtio_snd_ctrl_command`. They are stored in a queue field in the device
|
||||
* type, `VirtIOSound`. This allows deferring the CTRL request completion if
|
||||
* it's not immediately possible due to locking/state reasons.
|
||||
*
|
||||
* The CTRL message is finally handled in `process_cmd()`.
|
||||
*/
|
||||
struct VirtIOSound {
|
||||
VirtIODevice parent_obj;
|
||||
|
||||
VirtQueue *queues[VIRTIO_SND_VQ_MAX];
|
||||
uint64_t features;
|
||||
VirtIOSoundPCM *pcm;
|
||||
QEMUSoundCard card;
|
||||
VMChangeStateEntry *vmstate;
|
||||
virtio_snd_config snd_conf;
|
||||
QemuMutex cmdq_mutex;
|
||||
QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq;
|
||||
bool processing_cmdq;
|
||||
};
|
||||
|
||||
struct virtio_snd_ctrl_command {
|
||||
VirtQueueElement *elem;
|
||||
VirtQueue *vq;
|
||||
virtio_snd_hdr ctrl;
|
||||
virtio_snd_hdr resp;
|
||||
QTAILQ_ENTRY(virtio_snd_ctrl_command) next;
|
||||
};
|
||||
#endif
|
|
@ -61,4 +61,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(CXLHost, PXB_CXL_HOST)
|
|||
typedef struct CXLUpstreamPort CXLUpstreamPort;
|
||||
DECLARE_INSTANCE_CHECKER(CXLUpstreamPort, CXL_USP, TYPE_CXL_USP)
|
||||
CXLComponentState *cxl_usp_to_cstate(CXLUpstreamPort *usp);
|
||||
|
||||
#define TYPE_CXL_DSP "cxl-downstream"
|
||||
|
||||
typedef struct CXLDownstreamPort CXLDownstreamPort;
|
||||
DECLARE_INSTANCE_CHECKER(CXLDownstreamPort, CXL_DSP, TYPE_CXL_DSP)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,8 @@ enum reg_type {
|
|||
CXL2_LOGICAL_DEVICE,
|
||||
CXL2_ROOT_PORT,
|
||||
CXL2_UPSTREAM_PORT,
|
||||
CXL2_DOWNSTREAM_PORT
|
||||
CXL2_DOWNSTREAM_PORT,
|
||||
CXL3_SWITCH_MAILBOX_CCI,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -175,7 +176,8 @@ HDM_DECODER_INIT(3);
|
|||
(CXL_IDE_REGISTERS_OFFSET + CXL_IDE_REGISTERS_SIZE)
|
||||
#define CXL_SNOOP_REGISTERS_SIZE 0x8
|
||||
|
||||
QEMU_BUILD_BUG_MSG((CXL_SNOOP_REGISTERS_OFFSET + CXL_SNOOP_REGISTERS_SIZE) >= 0x1000,
|
||||
QEMU_BUILD_BUG_MSG((CXL_SNOOP_REGISTERS_OFFSET +
|
||||
CXL_SNOOP_REGISTERS_SIZE) >= 0x1000,
|
||||
"No space for registers");
|
||||
|
||||
typedef struct component_registers {
|
||||
|
|
|
@ -111,6 +111,20 @@ typedef enum {
|
|||
CXL_MBOX_MAX = 0x17
|
||||
} CXLRetCode;
|
||||
|
||||
typedef struct CXLCCI CXLCCI;
|
||||
typedef struct cxl_device_state CXLDeviceState;
|
||||
struct cxl_cmd;
|
||||
typedef CXLRetCode (*opcode_handler)(const struct cxl_cmd *cmd,
|
||||
uint8_t *payload_in, size_t len_in,
|
||||
uint8_t *payload_out, size_t *len_out,
|
||||
CXLCCI *cci);
|
||||
struct cxl_cmd {
|
||||
const char *name;
|
||||
opcode_handler handler;
|
||||
ssize_t in;
|
||||
uint16_t effect; /* Reported in CEL */
|
||||
};
|
||||
|
||||
typedef struct CXLEvent {
|
||||
CXLEventRecordRaw data;
|
||||
QSIMPLEQ_ENTRY(CXLEvent) node;
|
||||
|
@ -127,6 +141,31 @@ typedef struct CXLEventLog {
|
|||
QSIMPLEQ_HEAD(, CXLEvent) events;
|
||||
} CXLEventLog;
|
||||
|
||||
typedef struct CXLCCI {
|
||||
const struct cxl_cmd (*cxl_cmd_set)[256];
|
||||
struct cel_log {
|
||||
uint16_t opcode;
|
||||
uint16_t effect;
|
||||
} cel_log[1 << 16];
|
||||
size_t cel_size;
|
||||
|
||||
/* background command handling (times in ms) */
|
||||
struct {
|
||||
uint16_t opcode;
|
||||
uint16_t complete_pct;
|
||||
uint16_t ret_code; /* Current value of retcode */
|
||||
uint64_t starttime;
|
||||
/* set by each bg cmd, cleared by the bg_timer when complete */
|
||||
uint64_t runtime;
|
||||
QEMUTimer *timer;
|
||||
} bg;
|
||||
size_t payload_max;
|
||||
/* Pointer to device hosting the CCI */
|
||||
DeviceState *d;
|
||||
/* Pointer to the device hosting the protocol conversion */
|
||||
DeviceState *intf;
|
||||
} CXLCCI;
|
||||
|
||||
typedef struct cxl_device_state {
|
||||
MemoryRegion device_registers;
|
||||
|
||||
|
@ -154,17 +193,13 @@ typedef struct cxl_device_state {
|
|||
struct {
|
||||
MemoryRegion mailbox;
|
||||
uint16_t payload_size;
|
||||
uint8_t mbox_msi_n;
|
||||
union {
|
||||
uint8_t mbox_reg_state[CXL_MAILBOX_REGISTERS_LENGTH];
|
||||
uint16_t mbox_reg_state16[CXL_MAILBOX_REGISTERS_LENGTH / 2];
|
||||
uint32_t mbox_reg_state32[CXL_MAILBOX_REGISTERS_LENGTH / 4];
|
||||
uint64_t mbox_reg_state64[CXL_MAILBOX_REGISTERS_LENGTH / 8];
|
||||
};
|
||||
struct cel_log {
|
||||
uint16_t opcode;
|
||||
uint16_t effect;
|
||||
} cel_log[1 << 16];
|
||||
size_t cel_size;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -178,21 +213,26 @@ typedef struct cxl_device_state {
|
|||
uint64_t pmem_size;
|
||||
uint64_t vmem_size;
|
||||
|
||||
const struct cxl_cmd (*cxl_cmd_set)[256];
|
||||
CXLEventLog event_logs[CXL_EVENT_TYPE_MAX];
|
||||
} CXLDeviceState;
|
||||
|
||||
/* Initialize the register block for a device */
|
||||
void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev);
|
||||
void cxl_device_register_block_init(Object *obj, CXLDeviceState *dev,
|
||||
CXLCCI *cci);
|
||||
|
||||
typedef struct CXLType3Dev CXLType3Dev;
|
||||
typedef struct CSWMBCCIDev CSWMBCCIDev;
|
||||
/* Set up default values for the register block */
|
||||
void cxl_device_register_init_common(CXLDeviceState *dev);
|
||||
void cxl_device_register_init_t3(CXLType3Dev *ct3d);
|
||||
void cxl_device_register_init_swcci(CSWMBCCIDev *sw);
|
||||
|
||||
/*
|
||||
* CXL 2.0 - 8.2.8.1 including errata F4
|
||||
* Documented as a 128 bit register, but 64 bit accesses and the second
|
||||
* 64 bits are currently reserved.
|
||||
*/
|
||||
REG64(CXL_DEV_CAP_ARRAY, 0) /* Documented as 128 bit register but 64 byte accesses */
|
||||
REG64(CXL_DEV_CAP_ARRAY, 0)
|
||||
FIELD(CXL_DEV_CAP_ARRAY, CAP_ID, 0, 16)
|
||||
FIELD(CXL_DEV_CAP_ARRAY, CAP_VERSION, 16, 8)
|
||||
FIELD(CXL_DEV_CAP_ARRAY, CAP_COUNT, 32, 16)
|
||||
|
@ -231,8 +271,20 @@ CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE,
|
|||
CXL_DEVICE_CAP_HDR1_OFFSET +
|
||||
CXL_DEVICE_CAP_REG_SIZE * 2)
|
||||
|
||||
void cxl_initialize_mailbox(CXLDeviceState *cxl_dstate);
|
||||
void cxl_process_mailbox(CXLDeviceState *cxl_dstate);
|
||||
void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max);
|
||||
void cxl_initialize_mailbox_swcci(CXLCCI *cci, DeviceState *intf,
|
||||
DeviceState *d, size_t payload_max);
|
||||
void cxl_init_cci(CXLCCI *cci, size_t payload_max);
|
||||
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
||||
size_t len_in, uint8_t *pl_in,
|
||||
size_t *len_out, uint8_t *pl_out,
|
||||
bool *bg_started);
|
||||
void cxl_initialize_t3_fm_owned_ld_mctpcci(CXLCCI *cci, DeviceState *d,
|
||||
DeviceState *intf,
|
||||
size_t payload_max);
|
||||
|
||||
void cxl_initialize_t3_ld_cci(CXLCCI *cci, DeviceState *d,
|
||||
DeviceState *intf, size_t payload_max);
|
||||
|
||||
#define cxl_device_cap_init(dstate, reg, cap_id, ver) \
|
||||
do { \
|
||||
|
@ -297,6 +349,23 @@ REG64(CXL_MEM_DEV_STS, 0)
|
|||
FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1)
|
||||
FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3)
|
||||
|
||||
static inline void __toggle_media(CXLDeviceState *cxl_dstate, int val)
|
||||
{
|
||||
uint64_t dev_status_reg;
|
||||
|
||||
dev_status_reg = FIELD_DP64(0, CXL_MEM_DEV_STS, MEDIA_STATUS, val);
|
||||
cxl_dstate->mbox_reg_state64[R_CXL_MEM_DEV_STS] = dev_status_reg;
|
||||
}
|
||||
#define cxl_dev_disable_media(cxlds) \
|
||||
do { __toggle_media((cxlds), 0x3); } while (0)
|
||||
#define cxl_dev_enable_media(cxlds) \
|
||||
do { __toggle_media((cxlds), 0x1); } while (0)
|
||||
|
||||
static inline bool sanitize_running(CXLCCI *cci)
|
||||
{
|
||||
return !!cci->bg.runtime && cci->bg.opcode == 0x4400;
|
||||
}
|
||||
|
||||
typedef struct CXLError {
|
||||
QTAILQ_ENTRY(CXLError) node;
|
||||
int type; /* Error code as per FE definition */
|
||||
|
@ -333,6 +402,10 @@ struct CXLType3Dev {
|
|||
AddressSpace hostpmem_as;
|
||||
CXLComponentState cxl_cstate;
|
||||
CXLDeviceState cxl_dstate;
|
||||
CXLCCI cci; /* Primary PCI mailbox CCI */
|
||||
/* Always intialized as no way to know if a VDM might show up */
|
||||
CXLCCI vdm_fm_owned_ld_mctp_cci;
|
||||
CXLCCI ld0_cci;
|
||||
|
||||
/* DOE */
|
||||
DOECap doe_cdat;
|
||||
|
@ -361,9 +434,21 @@ struct CXLType3Class {
|
|||
uint64_t offset);
|
||||
void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size,
|
||||
uint64_t offset);
|
||||
bool (*set_cacheline)(CXLType3Dev *ct3d, uint64_t dpa_offset, uint8_t *data);
|
||||
bool (*set_cacheline)(CXLType3Dev *ct3d, uint64_t dpa_offset,
|
||||
uint8_t *data);
|
||||
};
|
||||
|
||||
struct CSWMBCCIDev {
|
||||
PCIDevice parent_obj;
|
||||
PCIDevice *target;
|
||||
CXLComponentState cxl_cstate;
|
||||
CXLDeviceState cxl_dstate;
|
||||
CXLCCI *cci;
|
||||
};
|
||||
|
||||
#define TYPE_CXL_SWITCH_MAILBOX_CCI "cxl-switch-mailbox-cci"
|
||||
OBJECT_DECLARE_TYPE(CSWMBCCIDev, CSWMBCCIClass, CXL_SWITCH_MAILBOX_CCI)
|
||||
|
||||
MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
|
||||
unsigned size, MemTxAttrs attrs);
|
||||
MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
|
||||
|
@ -376,7 +461,7 @@ bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type,
|
|||
CXLEventRecordRaw *event);
|
||||
CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl,
|
||||
uint8_t log_type, int max_recs,
|
||||
uint16_t *len);
|
||||
size_t *len);
|
||||
CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds,
|
||||
CXLClearEventPayload *pl);
|
||||
|
||||
|
|
|
@ -92,7 +92,8 @@ typedef enum CXLEventIntMode {
|
|||
CXL_INT_RES = 0x03,
|
||||
} CXLEventIntMode;
|
||||
#define CXL_EVENT_INT_MODE_MASK 0x3
|
||||
#define CXL_EVENT_INT_SETTING(vector) ((((uint8_t)vector & 0xf) << 4) | CXL_INT_MSI_MSIX)
|
||||
#define CXL_EVENT_INT_SETTING(vector) \
|
||||
((((uint8_t)vector & 0xf) << 4) | CXL_INT_MSI_MSIX)
|
||||
typedef struct CXLEventInterruptPolicy {
|
||||
uint8_t info_settings;
|
||||
uint8_t warn_settings;
|
||||
|
|
|
@ -86,7 +86,7 @@ typedef struct CXLDVSECDevice {
|
|||
QEMU_BUILD_BUG_ON(sizeof(CXLDVSECDevice) != 0x38);
|
||||
|
||||
/* CXL 2.0 - 8.1.5 (ID 0003) */
|
||||
typedef struct CXLDVSECPortExtensions {
|
||||
typedef struct CXLDVSECPortExt {
|
||||
DVSECHeader hdr;
|
||||
uint16_t status;
|
||||
uint16_t control;
|
||||
|
@ -100,8 +100,8 @@ typedef struct CXLDVSECPortExtensions {
|
|||
uint32_t alt_prefetch_limit_high;
|
||||
uint32_t rcrb_base;
|
||||
uint32_t rcrb_base_high;
|
||||
} CXLDVSECPortExtensions;
|
||||
QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortExtensions) != 0x28);
|
||||
} CXLDVSECPortExt;
|
||||
QEMU_BUILD_BUG_ON(sizeof(CXLDVSECPortExt) != 0x28);
|
||||
|
||||
#define PORT_CONTROL_OFFSET 0xc
|
||||
#define PORT_CONTROL_UNMASK_SBR 1
|
||||
|
|
19
include/hw/pci-bridge/cxl_upstream_port.h
Normal file
19
include/hw/pci-bridge/cxl_upstream_port.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
#ifndef CXL_USP_H
|
||||
#define CXL_USP_H
|
||||
#include "hw/pci/pcie.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
|
||||
typedef struct CXLUpstreamPort {
|
||||
/*< private >*/
|
||||
PCIEPort parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
CXLComponentState cxl_cstate;
|
||||
CXLCCI swcci;
|
||||
DOECap doe_cdat;
|
||||
uint64_t sn;
|
||||
} CXLUpstreamPort;
|
||||
|
||||
#endif /* CXL_SUP_H */
|
|
@ -26,6 +26,18 @@ typedef enum VhostSetConfigType {
|
|||
VHOST_SET_CONFIG_TYPE_MIGRATION = 1,
|
||||
} VhostSetConfigType;
|
||||
|
||||
typedef enum VhostDeviceStateDirection {
|
||||
/* Transfer state from back-end (device) to front-end */
|
||||
VHOST_TRANSFER_STATE_DIRECTION_SAVE = 0,
|
||||
/* Transfer state from front-end to back-end (device) */
|
||||
VHOST_TRANSFER_STATE_DIRECTION_LOAD = 1,
|
||||
} VhostDeviceStateDirection;
|
||||
|
||||
typedef enum VhostDeviceStatePhase {
|
||||
/* The device (and all its vrings) is stopped */
|
||||
VHOST_TRANSFER_STATE_PHASE_STOPPED = 0,
|
||||
} VhostDeviceStatePhase;
|
||||
|
||||
struct vhost_inflight;
|
||||
struct vhost_dev;
|
||||
struct vhost_log;
|
||||
|
@ -129,6 +141,15 @@ typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev,
|
|||
|
||||
typedef void (*vhost_reset_status_op)(struct vhost_dev *dev);
|
||||
|
||||
typedef bool (*vhost_supports_device_state_op)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_set_device_state_fd_op)(struct vhost_dev *dev,
|
||||
VhostDeviceStateDirection direction,
|
||||
VhostDeviceStatePhase phase,
|
||||
int fd,
|
||||
int *reply_fd,
|
||||
Error **errp);
|
||||
typedef int (*vhost_check_device_state_op)(struct vhost_dev *dev, Error **errp);
|
||||
|
||||
typedef struct VhostOps {
|
||||
VhostBackendType backend_type;
|
||||
vhost_backend_init vhost_backend_init;
|
||||
|
@ -176,6 +197,9 @@ typedef struct VhostOps {
|
|||
vhost_force_iommu_op vhost_force_iommu;
|
||||
vhost_set_config_call_op vhost_set_config_call;
|
||||
vhost_reset_status_op vhost_reset_status;
|
||||
vhost_supports_device_state_op vhost_supports_device_state;
|
||||
vhost_set_device_state_fd_op vhost_set_device_state_fd;
|
||||
vhost_check_device_state_op vhost_check_device_state;
|
||||
} VhostOps;
|
||||
|
||||
int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
|
||||
|
|
|
@ -31,6 +31,7 @@ enum VhostUserProtocolFeature {
|
|||
VHOST_USER_PROTOCOL_F_STATUS = 16,
|
||||
/* Feature 17 reserved for VHOST_USER_PROTOCOL_F_XEN_MMAP. */
|
||||
VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 18,
|
||||
VHOST_USER_PROTOCOL_F_DEVICE_STATE = 19,
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -351,4 +351,117 @@ static inline int vhost_reset_device(struct vhost_dev *hdev)
|
|||
}
|
||||
#endif /* CONFIG_VHOST */
|
||||
|
||||
/**
|
||||
* vhost_supports_device_state(): Checks whether the back-end supports
|
||||
* transferring internal device state for the purpose of migration.
|
||||
* Support for this feature is required for vhost_set_device_state_fd()
|
||||
* and vhost_check_device_state().
|
||||
*
|
||||
* @dev: The vhost device
|
||||
*
|
||||
* Returns true if the device supports these commands, and false if it
|
||||
* does not.
|
||||
*/
|
||||
bool vhost_supports_device_state(struct vhost_dev *dev);
|
||||
|
||||
/**
|
||||
* vhost_set_device_state_fd(): Begin transfer of internal state from/to
|
||||
* the back-end for the purpose of migration. Data is to be transferred
|
||||
* over a pipe according to @direction and @phase. The sending end must
|
||||
* only write to the pipe, and the receiving end must only read from it.
|
||||
* Once the sending end is done, it closes its FD. The receiving end
|
||||
* must take this as the end-of-transfer signal and close its FD, too.
|
||||
*
|
||||
* @fd is the back-end's end of the pipe: The write FD for SAVE, and the
|
||||
* read FD for LOAD. This function transfers ownership of @fd to the
|
||||
* back-end, i.e. closes it in the front-end.
|
||||
*
|
||||
* The back-end may optionally reply with an FD of its own, if this
|
||||
* improves efficiency on its end. In this case, the returned FD is
|
||||
* stored in *reply_fd. The back-end will discard the FD sent to it,
|
||||
* and the front-end must use *reply_fd for transferring state to/from
|
||||
* the back-end.
|
||||
*
|
||||
* @dev: The vhost device
|
||||
* @direction: The direction in which the state is to be transferred.
|
||||
* For outgoing migrations, this is SAVE, and data is read
|
||||
* from the back-end and stored by the front-end in the
|
||||
* migration stream.
|
||||
* For incoming migrations, this is LOAD, and data is read
|
||||
* by the front-end from the migration stream and sent to
|
||||
* the back-end to restore the saved state.
|
||||
* @phase: Which migration phase we are in. Currently, there is only
|
||||
* STOPPED (device and all vrings are stopped), in the future,
|
||||
* more phases such as PRE_COPY or POST_COPY may be added.
|
||||
* @fd: Back-end's end of the pipe through which to transfer state; note
|
||||
* that ownership is transferred to the back-end, so this function
|
||||
* closes @fd in the front-end.
|
||||
* @reply_fd: If the back-end wishes to use a different pipe for state
|
||||
* transfer, this will contain an FD for the front-end to
|
||||
* use. Otherwise, -1 is stored here.
|
||||
* @errp: Potential error description
|
||||
*
|
||||
* Returns 0 on success, and -errno on failure.
|
||||
*/
|
||||
int vhost_set_device_state_fd(struct vhost_dev *dev,
|
||||
VhostDeviceStateDirection direction,
|
||||
VhostDeviceStatePhase phase,
|
||||
int fd,
|
||||
int *reply_fd,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* vhost_set_device_state_fd(): After transferring state from/to the
|
||||
* back-end via vhost_set_device_state_fd(), i.e. once the sending end
|
||||
* has closed the pipe, inquire the back-end to report any potential
|
||||
* errors that have occurred on its side. This allows to sense errors
|
||||
* like:
|
||||
* - During outgoing migration, when the source side had already started
|
||||
* to produce its state, something went wrong and it failed to finish
|
||||
* - During incoming migration, when the received state is somehow
|
||||
* invalid and cannot be processed by the back-end
|
||||
*
|
||||
* @dev: The vhost device
|
||||
* @errp: Potential error description
|
||||
*
|
||||
* Returns 0 when the back-end reports successful state transfer and
|
||||
* processing, and -errno when an error occurred somewhere.
|
||||
*/
|
||||
int vhost_check_device_state(struct vhost_dev *dev, Error **errp);
|
||||
|
||||
/**
|
||||
* vhost_save_backend_state(): High-level function to receive a vhost
|
||||
* back-end's state, and save it in @f. Uses
|
||||
* `vhost_set_device_state_fd()` to get the data from the back-end, and
|
||||
* stores it in consecutive chunks that are each prefixed by their
|
||||
* respective length (be32). The end is marked by a 0-length chunk.
|
||||
*
|
||||
* Must only be called while the device and all its vrings are stopped
|
||||
* (`VHOST_TRANSFER_STATE_PHASE_STOPPED`).
|
||||
*
|
||||
* @dev: The vhost device from which to save the state
|
||||
* @f: Migration stream in which to save the state
|
||||
* @errp: Potential error message
|
||||
*
|
||||
* Returns 0 on success, and -errno otherwise.
|
||||
*/
|
||||
int vhost_save_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
||||
|
||||
/**
|
||||
* vhost_load_backend_state(): High-level function to load a vhost
|
||||
* back-end's state from @f, and send it over to the back-end. Reads
|
||||
* the data from @f in the format used by `vhost_save_state()`, and uses
|
||||
* `vhost_set_device_state_fd()` to transfer it to the back-end.
|
||||
*
|
||||
* Must only be called while the device and all its vrings are stopped
|
||||
* (`VHOST_TRANSFER_STATE_PHASE_STOPPED`).
|
||||
*
|
||||
* @dev: The vhost device to which to send the sate
|
||||
* @f: Migration stream from which to load the state
|
||||
* @errp: Potential error message
|
||||
*
|
||||
* Returns 0 on success, and -errno otherwise.
|
||||
*/
|
||||
int vhost_load_backend_state(struct vhost_dev *dev, QEMUFile *f, Error **errp);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue