mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/marcel/tags/rdma-pull-request' into staging
RDMA queue * Add support for RDMA MAD * Various fixes for the pvrdma backend # gpg: Signature made Sat 22 Dec 2018 09:36:36 GMT # gpg: using RSA key 36D4C0F0CF2FE46D # gpg: Good signature from "Marcel Apfelbaum <marcel.apfelbaum@zoho.com>" # gpg: aka "Marcel Apfelbaum <marcel@redhat.com>" # gpg: aka "Marcel Apfelbaum <marcel.apfelbaum@gmail.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: B1C6 3A57 F92E 08F2 640F 31F5 36D4 C0F0 CF2F E46D * remotes/marcel/tags/rdma-pull-request: (31 commits) pvrdma: check return value from pvrdma_idx_ring_has_ routines rdma: remove unused VENDOR_ERR_NO_SGE macro pvrdma: release ring object in case of an error pvrdma: check number of pages when creating rings pvrdma: add uar_read routine rdma: check num_sge does not exceed MAX_SGE pvrdma: release device resources in case of an error docs: Update pvrdma device documentation hw/rdma: Do not call rdma_backend_del_gid on an empty gid hw/rdma: Do not use bitmap_zero_extend to free bitmap hw/pvrdma: Clean device's resource when system is shutdown vl: Introduce shutdown_notifiers hw/rdma: Remove unneeded code that handles more that one port hw/pvrdma: Fill error code in command's response hw/pvrdma: Fill all CQE fields hw/pvrdma: Make device state depend on Ethernet function state hw/rdma: Initialize node_guid from vmxnet3 mac address hw/pvrdma: Make sure PCI function 0 is vmxnet3 vmxnet3: Move some definitions to header file hw/pvrdma: Add support to allow guest to configure GID table ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -2412,6 +2412,8 @@ S: Maintained
|
||||
F: hw/rdma/*
|
||||
F: hw/rdma/vmw/*
|
||||
F: docs/pvrdma.txt
|
||||
F: contrib/rdmacm-mux/*
|
||||
F: qapi/rdma.json
|
||||
|
||||
Build and test automation
|
||||
-------------------------
|
||||
|
||||
@@ -362,6 +362,7 @@ dummy := $(call unnest-vars,, \
|
||||
elf2dmp-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
rdmacm-mux-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
vhost-user-blk-obj-y \
|
||||
@@ -579,6 +580,8 @@ vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||
$(call quiet-command,$(PYTHON) $< $@ \
|
||||
|
||||
+3
-1
@@ -1,5 +1,6 @@
|
||||
QAPI_MODULES = block-core block char common crypto introspect job migration
|
||||
QAPI_MODULES += misc net rocker run-state sockets tpm trace transaction ui
|
||||
QAPI_MODULES += misc net rdma rocker run-state sockets tpm trace transaction
|
||||
QAPI_MODULES += ui
|
||||
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
@@ -133,6 +134,7 @@ vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
|
||||
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
|
||||
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ifdef CONFIG_PVRDMA
|
||||
CFLAGS += -libumad -Wno-format-truncation
|
||||
rdmacm-mux-obj-y = main.o
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QEMU paravirtual RDMA - rdmacm-mux declarations
|
||||
*
|
||||
* Copyright (C) 2018 Oracle
|
||||
* Copyright (C) 2018 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Yuval Shaia <yuval.shaia@oracle.com>
|
||||
* Marcel Apfelbaum <marcel@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RDMACM_MUX_H
|
||||
#define RDMACM_MUX_H
|
||||
|
||||
#include "linux/if.h"
|
||||
#include "infiniband/verbs.h"
|
||||
#include "infiniband/umad.h"
|
||||
#include "rdma/rdma_user_cm.h"
|
||||
|
||||
typedef enum RdmaCmMuxMsgType {
|
||||
RDMACM_MUX_MSG_TYPE_REQ = 0,
|
||||
RDMACM_MUX_MSG_TYPE_RESP = 1,
|
||||
} RdmaCmMuxMsgType;
|
||||
|
||||
typedef enum RdmaCmMuxOpCode {
|
||||
RDMACM_MUX_OP_CODE_REG = 0,
|
||||
RDMACM_MUX_OP_CODE_UNREG = 1,
|
||||
RDMACM_MUX_OP_CODE_MAD = 2,
|
||||
} RdmaCmMuxOpCode;
|
||||
|
||||
typedef enum RdmaCmMuxErrCode {
|
||||
RDMACM_MUX_ERR_CODE_OK = 0,
|
||||
RDMACM_MUX_ERR_CODE_EINVAL = 1,
|
||||
RDMACM_MUX_ERR_CODE_EEXIST = 2,
|
||||
RDMACM_MUX_ERR_CODE_EACCES = 3,
|
||||
RDMACM_MUX_ERR_CODE_ENOTFOUND = 4,
|
||||
} RdmaCmMuxErrCode;
|
||||
|
||||
typedef struct RdmaCmMuxHdr {
|
||||
RdmaCmMuxMsgType msg_type;
|
||||
RdmaCmMuxOpCode op_code;
|
||||
union ibv_gid sgid;
|
||||
RdmaCmMuxErrCode err_code;
|
||||
} RdmaCmUHdr;
|
||||
|
||||
typedef struct RdmaCmUMad {
|
||||
struct ib_user_mad hdr;
|
||||
char mad[RDMA_MAX_PRIVATE_DATA];
|
||||
} RdmaCmUMad;
|
||||
|
||||
typedef struct RdmaCmMuxMsg {
|
||||
RdmaCmUHdr hdr;
|
||||
int umad_len;
|
||||
RdmaCmUMad umad;
|
||||
} RdmaCmMuxMsg;
|
||||
|
||||
#endif
|
||||
+107
-19
@@ -9,8 +9,9 @@ It works with its Linux Kernel driver AS IS, no need for any special guest
|
||||
modifications.
|
||||
|
||||
While it complies with the VMware device, it can also communicate with bare
|
||||
metal RDMA-enabled machines and does not require an RDMA HCA in the host, it
|
||||
can work with Soft-RoCE (rxe).
|
||||
metal RDMA-enabled machines as peers.
|
||||
|
||||
It does not require an RDMA HCA in the host, it can work with Soft-RoCE (rxe).
|
||||
|
||||
It does not require the whole guest RAM to be pinned allowing memory
|
||||
over-commit and, even if not implemented yet, migration support will be
|
||||
@@ -78,29 +79,116 @@ the required RDMA libraries.
|
||||
|
||||
3. Usage
|
||||
========
|
||||
|
||||
|
||||
3.1 VM Memory settings
|
||||
======================
|
||||
Currently the device is working only with memory backed RAM
|
||||
and it must be mark as "shared":
|
||||
-m 1G \
|
||||
-object memory-backend-ram,id=mb1,size=1G,share \
|
||||
-numa node,memdev=mb1 \
|
||||
|
||||
The pvrdma device is composed of two functions:
|
||||
- Function 0 is a vmxnet Ethernet Device which is redundant in Guest
|
||||
but is required to pass the ibdevice GID using its MAC.
|
||||
Examples:
|
||||
For an rxe backend using eth0 interface it will use its mac:
|
||||
-device vmxnet3,addr=<slot>.0,multifunction=on,mac=<eth0 MAC>
|
||||
For an SRIOV VF, we take the Ethernet Interface exposed by it:
|
||||
-device vmxnet3,multifunction=on,mac=<RoCE eth MAC>
|
||||
- Function 1 is the actual device:
|
||||
-device pvrdma,addr=<slot>.1,backend-dev=<ibdevice>,backend-gid-idx=<gid>,backend-port=<port>
|
||||
where the ibdevice can be rxe or RDMA VF (e.g. mlx5_4)
|
||||
Note: Pay special attention that the GID at backend-gid-idx matches vmxnet's MAC.
|
||||
The rules of conversion are part of the RoCE spec, but since manual conversion
|
||||
is not required, spotting problems is not hard:
|
||||
Example: GID: fe80:0000:0000:0000:7efe:90ff:fecb:743a
|
||||
MAC: 7c:fe:90:cb:74:3a
|
||||
Note the difference between the first byte of the MAC and the GID.
|
||||
|
||||
3.2 MAD Multiplexer
|
||||
===================
|
||||
MAD Multiplexer is a service that exposes MAD-like interface for VMs in
|
||||
order to overcome the limitation where only single entity can register with
|
||||
MAD layer to send and receive RDMA-CM MAD packets.
|
||||
|
||||
To build rdmacm-mux run
|
||||
# make rdmacm-mux
|
||||
|
||||
The application accepts 3 command line arguments and exposes a UNIX socket
|
||||
to pass control and data to it.
|
||||
-d rdma-device-name Name of RDMA device to register with
|
||||
-s unix-socket-path Path to unix socket to listen (default /var/run/rdmacm-mux)
|
||||
-p rdma-device-port Port number of RDMA device to register with (default 1)
|
||||
The final UNIX socket file name is a concatenation of the 3 arguments so
|
||||
for example for device mlx5_0 on port 2 this /var/run/rdmacm-mux-mlx5_0-2
|
||||
will be created.
|
||||
|
||||
pvrdma requires this service.
|
||||
|
||||
Please refer to contrib/rdmacm-mux for more details.
|
||||
|
||||
|
||||
3.3 Service exposed by libvirt daemon
|
||||
=====================================
|
||||
The control over the RDMA device's GID table is done by updating the
|
||||
device's Ethernet function addresses.
|
||||
Usually the first GID entry is determined by the MAC address, the second by
|
||||
the first IPv6 address and the third by the IPv4 address. Other entries can
|
||||
be added by adding more IP addresses. The opposite is the same, i.e.
|
||||
whenever an address is removed, the corresponding GID entry is removed.
|
||||
The process is done by the network and RDMA stacks. Whenever an address is
|
||||
added the ib_core driver is notified and calls the device driver add_gid
|
||||
function which in turn update the device.
|
||||
To support this in pvrdma device the device hooks into the create_bind and
|
||||
destroy_bind HW commands triggered by pvrdma driver in guest.
|
||||
|
||||
Whenever changed is made to the pvrdma port's GID table a special QMP
|
||||
messages is sent to be processed by libvirt to update the address of the
|
||||
backend Ethernet device.
|
||||
|
||||
pvrdma requires that libvirt service will be up.
|
||||
|
||||
|
||||
3.4 PCI devices settings
|
||||
========================
|
||||
RoCE device exposes two functions - an Ethernet and RDMA.
|
||||
To support it, pvrdma device is composed of two PCI functions, an Ethernet
|
||||
device of type vmxnet3 on PCI slot 0 and a PVRDMA device on PCI slot 1. The
|
||||
Ethernet function can be used for other Ethernet purposes such as IP.
|
||||
|
||||
|
||||
3.5 Device parameters
|
||||
=====================
|
||||
- netdev: Specifies the Ethernet device function name on the host for
|
||||
example enp175s0f0. For Soft-RoCE device (rxe) this would be the Ethernet
|
||||
device used to create it.
|
||||
- ibdev: The IB device name on host for example rxe0, mlx5_0 etc.
|
||||
- mad-chardev: The name of the MAD multiplexer char device.
|
||||
- ibport: In case of multi-port device (such as Mellanox's HCA) this
|
||||
specify the port to use. If not set 1 will be used.
|
||||
- dev-caps-max-mr-size: The maximum size of MR.
|
||||
- dev-caps-max-qp: Maximum number of QPs.
|
||||
- dev-caps-max-sge: Maximum number of SGE elements in WR.
|
||||
- dev-caps-max-cq: Maximum number of CQs.
|
||||
- dev-caps-max-mr: Maximum number of MRs.
|
||||
- dev-caps-max-pd: Maximum number of PDs.
|
||||
- dev-caps-max-ah: Maximum number of AHs.
|
||||
|
||||
Notes:
|
||||
- The first 3 parameters are mandatory settings, the rest have their
|
||||
defaults.
|
||||
- The last 8 parameters (the ones that prefixed by dev-caps) defines the top
|
||||
limits but the final values is adjusted by the backend device limitations.
|
||||
- netdev can be extracted from ibdev's sysfs
|
||||
(/sys/class/infiniband/<ibdev>/device/net/)
|
||||
|
||||
|
||||
3.6 Example
|
||||
===========
|
||||
Define bridge device with vmxnet3 network backend:
|
||||
<interface type='bridge'>
|
||||
<mac address='56:b4:44:e9:62:dc'/>
|
||||
<source bridge='bridge1'/>
|
||||
<model type='vmxnet3'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0' multifunction='on'/>
|
||||
</interface>
|
||||
|
||||
Define pvrdma device:
|
||||
<qemu:commandline>
|
||||
<qemu:arg value='-object'/>
|
||||
<qemu:arg value='memory-backend-ram,id=mb1,size=1G,share'/>
|
||||
<qemu:arg value='-numa'/>
|
||||
<qemu:arg value='node,memdev=mb1'/>
|
||||
<qemu:arg value='-chardev'/>
|
||||
<qemu:arg value='socket,path=/var/run/rdmacm-mux-rxe0-1,id=mads'/>
|
||||
<qemu:arg value='-device'/>
|
||||
<qemu:arg value='pvrdma,addr=10.1,ibdev=rxe0,netdev=bridge0,mad-chardev=mads'/>
|
||||
</qemu:commandline>
|
||||
|
||||
|
||||
|
||||
|
||||
+1
-115
@@ -18,7 +18,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "net/net.h"
|
||||
#include "net/tap.h"
|
||||
#include "net/checksum.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@@ -29,6 +28,7 @@
|
||||
#include "migration/register.h"
|
||||
|
||||
#include "vmxnet3.h"
|
||||
#include "vmxnet3_defs.h"
|
||||
#include "vmxnet_debug.h"
|
||||
#include "vmware_utils.h"
|
||||
#include "net_tx_pkt.h"
|
||||
@@ -131,23 +131,11 @@ typedef struct VMXNET3Class {
|
||||
DeviceRealize parent_dc_realize;
|
||||
} VMXNET3Class;
|
||||
|
||||
#define TYPE_VMXNET3 "vmxnet3"
|
||||
#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
|
||||
|
||||
#define VMXNET3_DEVICE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VMXNET3Class, (klass), TYPE_VMXNET3)
|
||||
#define VMXNET3_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VMXNET3Class, (obj), TYPE_VMXNET3)
|
||||
|
||||
/* Cyclic ring abstraction */
|
||||
typedef struct {
|
||||
hwaddr pa;
|
||||
uint32_t size;
|
||||
uint32_t cell_size;
|
||||
uint32_t next;
|
||||
uint8_t gen;
|
||||
} Vmxnet3Ring;
|
||||
|
||||
static inline void vmxnet3_ring_init(PCIDevice *d,
|
||||
Vmxnet3Ring *ring,
|
||||
hwaddr pa,
|
||||
@@ -245,108 +233,6 @@ vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr)
|
||||
descr->rsvd, descr->dtype, descr->ext1, descr->btype);
|
||||
}
|
||||
|
||||
/* Device state and helper functions */
|
||||
#define VMXNET3_RX_RINGS_PER_QUEUE (2)
|
||||
|
||||
typedef struct {
|
||||
Vmxnet3Ring tx_ring;
|
||||
Vmxnet3Ring comp_ring;
|
||||
|
||||
uint8_t intr_idx;
|
||||
hwaddr tx_stats_pa;
|
||||
struct UPT1_TxStats txq_stats;
|
||||
} Vmxnet3TxqDescr;
|
||||
|
||||
typedef struct {
|
||||
Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
|
||||
Vmxnet3Ring comp_ring;
|
||||
uint8_t intr_idx;
|
||||
hwaddr rx_stats_pa;
|
||||
struct UPT1_RxStats rxq_stats;
|
||||
} Vmxnet3RxqDescr;
|
||||
|
||||
typedef struct {
|
||||
bool is_masked;
|
||||
bool is_pending;
|
||||
bool is_asserted;
|
||||
} Vmxnet3IntState;
|
||||
|
||||
typedef struct {
|
||||
PCIDevice parent_obj;
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
MemoryRegion bar0;
|
||||
MemoryRegion bar1;
|
||||
MemoryRegion msix_bar;
|
||||
|
||||
Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
|
||||
Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
|
||||
|
||||
/* Whether MSI-X support was installed successfully */
|
||||
bool msix_used;
|
||||
hwaddr drv_shmem;
|
||||
hwaddr temp_shared_guest_driver_memory;
|
||||
|
||||
uint8_t txq_num;
|
||||
|
||||
/* This boolean tells whether RX packet being indicated has to */
|
||||
/* be split into head and body chunks from different RX rings */
|
||||
bool rx_packets_compound;
|
||||
|
||||
bool rx_vlan_stripping;
|
||||
bool lro_supported;
|
||||
|
||||
uint8_t rxq_num;
|
||||
|
||||
/* Network MTU */
|
||||
uint32_t mtu;
|
||||
|
||||
/* Maximum number of fragments for indicated TX packets */
|
||||
uint32_t max_tx_frags;
|
||||
|
||||
/* Maximum number of fragments for indicated RX packets */
|
||||
uint16_t max_rx_frags;
|
||||
|
||||
/* Index for events interrupt */
|
||||
uint8_t event_int_idx;
|
||||
|
||||
/* Whether automatic interrupts masking enabled */
|
||||
bool auto_int_masking;
|
||||
|
||||
bool peer_has_vhdr;
|
||||
|
||||
/* TX packets to QEMU interface */
|
||||
struct NetTxPkt *tx_pkt;
|
||||
uint32_t offload_mode;
|
||||
uint32_t cso_or_gso_size;
|
||||
uint16_t tci;
|
||||
bool needs_vlan;
|
||||
|
||||
struct NetRxPkt *rx_pkt;
|
||||
|
||||
bool tx_sop;
|
||||
bool skip_current_tx_pkt;
|
||||
|
||||
uint32_t device_active;
|
||||
uint32_t last_command;
|
||||
|
||||
uint32_t link_status_and_speed;
|
||||
|
||||
Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
|
||||
|
||||
uint32_t temp_mac; /* To store the low part first */
|
||||
|
||||
MACAddr perm_mac;
|
||||
uint32_t vlan_table[VMXNET3_VFT_SIZE];
|
||||
uint32_t rx_mode;
|
||||
MACAddr *mcast_list;
|
||||
uint32_t mcast_list_len;
|
||||
uint32_t mcast_list_buff_size; /* needed for live migration. */
|
||||
|
||||
/* Compatibility flags for migration */
|
||||
uint32_t compat_flags;
|
||||
} VMXNET3State;
|
||||
|
||||
/* Interrupt management */
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* QEMU VMWARE VMXNET3 paravirtual NIC
|
||||
*
|
||||
* Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
|
||||
*
|
||||
* Developed by Daynix Computing LTD (http://www.daynix.com)
|
||||
*
|
||||
* Authors:
|
||||
* Dmitry Fleytman <dmitry@daynix.com>
|
||||
* Tamir Shomer <tamirs@daynix.com>
|
||||
* Yan Vugenfirer <yan@daynix.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "net/net.h"
|
||||
#include "hw/net/vmxnet3.h"
|
||||
|
||||
#define TYPE_VMXNET3 "vmxnet3"
|
||||
#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
|
||||
|
||||
/* Device state and helper functions */
|
||||
#define VMXNET3_RX_RINGS_PER_QUEUE (2)
|
||||
|
||||
/* Cyclic ring abstraction */
|
||||
typedef struct {
|
||||
hwaddr pa;
|
||||
uint32_t size;
|
||||
uint32_t cell_size;
|
||||
uint32_t next;
|
||||
uint8_t gen;
|
||||
} Vmxnet3Ring;
|
||||
|
||||
typedef struct {
|
||||
Vmxnet3Ring tx_ring;
|
||||
Vmxnet3Ring comp_ring;
|
||||
|
||||
uint8_t intr_idx;
|
||||
hwaddr tx_stats_pa;
|
||||
struct UPT1_TxStats txq_stats;
|
||||
} Vmxnet3TxqDescr;
|
||||
|
||||
typedef struct {
|
||||
Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
|
||||
Vmxnet3Ring comp_ring;
|
||||
uint8_t intr_idx;
|
||||
hwaddr rx_stats_pa;
|
||||
struct UPT1_RxStats rxq_stats;
|
||||
} Vmxnet3RxqDescr;
|
||||
|
||||
typedef struct {
|
||||
bool is_masked;
|
||||
bool is_pending;
|
||||
bool is_asserted;
|
||||
} Vmxnet3IntState;
|
||||
|
||||
typedef struct {
|
||||
PCIDevice parent_obj;
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
MemoryRegion bar0;
|
||||
MemoryRegion bar1;
|
||||
MemoryRegion msix_bar;
|
||||
|
||||
Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
|
||||
Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
|
||||
|
||||
/* Whether MSI-X support was installed successfully */
|
||||
bool msix_used;
|
||||
hwaddr drv_shmem;
|
||||
hwaddr temp_shared_guest_driver_memory;
|
||||
|
||||
uint8_t txq_num;
|
||||
|
||||
/* This boolean tells whether RX packet being indicated has to */
|
||||
/* be split into head and body chunks from different RX rings */
|
||||
bool rx_packets_compound;
|
||||
|
||||
bool rx_vlan_stripping;
|
||||
bool lro_supported;
|
||||
|
||||
uint8_t rxq_num;
|
||||
|
||||
/* Network MTU */
|
||||
uint32_t mtu;
|
||||
|
||||
/* Maximum number of fragments for indicated TX packets */
|
||||
uint32_t max_tx_frags;
|
||||
|
||||
/* Maximum number of fragments for indicated RX packets */
|
||||
uint16_t max_rx_frags;
|
||||
|
||||
/* Index for events interrupt */
|
||||
uint8_t event_int_idx;
|
||||
|
||||
/* Whether automatic interrupts masking enabled */
|
||||
bool auto_int_masking;
|
||||
|
||||
bool peer_has_vhdr;
|
||||
|
||||
/* TX packets to QEMU interface */
|
||||
struct NetTxPkt *tx_pkt;
|
||||
uint32_t offload_mode;
|
||||
uint32_t cso_or_gso_size;
|
||||
uint16_t tci;
|
||||
bool needs_vlan;
|
||||
|
||||
struct NetRxPkt *rx_pkt;
|
||||
|
||||
bool tx_sop;
|
||||
bool skip_current_tx_pkt;
|
||||
|
||||
uint32_t device_active;
|
||||
uint32_t last_command;
|
||||
|
||||
uint32_t link_status_and_speed;
|
||||
|
||||
Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
|
||||
|
||||
uint32_t temp_mac; /* To store the low part first */
|
||||
|
||||
MACAddr perm_mac;
|
||||
uint32_t vlan_table[VMXNET3_VFT_SIZE];
|
||||
uint32_t rx_mode;
|
||||
MACAddr *mcast_list;
|
||||
uint32_t mcast_list_len;
|
||||
uint32_t mcast_list_buff_size; /* needed for live migration. */
|
||||
|
||||
/* Compatibility flags for migration */
|
||||
uint32_t compat_flags;
|
||||
} VMXNET3State;
|
||||
+460
-64
File diff suppressed because it is too large
Load Diff
+16
-12
@@ -17,6 +17,8 @@
|
||||
#define RDMA_BACKEND_H
|
||||
|
||||
#include "qapi/error.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
#include "rdma_rm_defs.h"
|
||||
#include "rdma_backend_defs.h"
|
||||
|
||||
@@ -26,14 +28,9 @@ enum ibv_special_qp_type {
|
||||
IBV_QPT_GSI = 1,
|
||||
};
|
||||
|
||||
static inline union ibv_gid *rdma_backend_gid(RdmaBackendDev *dev)
|
||||
{
|
||||
return &dev->gid;
|
||||
}
|
||||
|
||||
static inline uint32_t rdma_backend_qpn(const RdmaBackendQP *qp)
|
||||
{
|
||||
return qp->ibqp ? qp->ibqp->qp_num : 0;
|
||||
return qp->ibqp ? qp->ibqp->qp_num : 1;
|
||||
}
|
||||
|
||||
static inline uint32_t rdma_backend_mr_lkey(const RdmaBackendMR *mr)
|
||||
@@ -49,13 +46,19 @@ static inline uint32_t rdma_backend_mr_rkey(const RdmaBackendMR *mr)
|
||||
int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
|
||||
RdmaDeviceResources *rdma_dev_res,
|
||||
const char *backend_device_name, uint8_t port_num,
|
||||
uint8_t backend_gid_idx, struct ibv_device_attr *dev_attr,
|
||||
struct ibv_device_attr *dev_attr, CharBackend *mad_chr_be,
|
||||
Error **errp);
|
||||
void rdma_backend_fini(RdmaBackendDev *backend_dev);
|
||||
int rdma_backend_add_gid(RdmaBackendDev *backend_dev, const char *ifname,
|
||||
union ibv_gid *gid);
|
||||
int rdma_backend_del_gid(RdmaBackendDev *backend_dev, const char *ifname,
|
||||
union ibv_gid *gid);
|
||||
int rdma_backend_get_gid_index(RdmaBackendDev *backend_dev,
|
||||
union ibv_gid *gid);
|
||||
void rdma_backend_start(RdmaBackendDev *backend_dev);
|
||||
void rdma_backend_stop(RdmaBackendDev *backend_dev);
|
||||
void rdma_backend_register_comp_handler(void (*handler)(int status,
|
||||
unsigned int vendor_err, void *ctx));
|
||||
void rdma_backend_register_comp_handler(void (*handler)(void *ctx,
|
||||
struct ibv_wc *wc));
|
||||
void rdma_backend_unregister_comp_handler(void);
|
||||
|
||||
int rdma_backend_query_port(RdmaBackendDev *backend_dev,
|
||||
@@ -80,9 +83,9 @@ int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
|
||||
int rdma_backend_qp_state_init(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
|
||||
uint8_t qp_type, uint32_t qkey);
|
||||
int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
|
||||
uint8_t qp_type, union ibv_gid *dgid,
|
||||
uint32_t dqpn, uint32_t rq_psn, uint32_t qkey,
|
||||
bool use_qkey);
|
||||
uint8_t qp_type, uint8_t sgid_idx,
|
||||
union ibv_gid *dgid, uint32_t dqpn,
|
||||
uint32_t rq_psn, uint32_t qkey, bool use_qkey);
|
||||
int rdma_backend_qp_state_rts(RdmaBackendQP *qp, uint8_t qp_type,
|
||||
uint32_t sq_psn, uint32_t qkey, bool use_qkey);
|
||||
int rdma_backend_query_qp(RdmaBackendQP *qp, struct ibv_qp_attr *attr,
|
||||
@@ -92,6 +95,7 @@ void rdma_backend_destroy_qp(RdmaBackendQP *qp);
|
||||
void rdma_backend_post_send(RdmaBackendDev *backend_dev,
|
||||
RdmaBackendQP *qp, uint8_t qp_type,
|
||||
struct ibv_sge *sge, uint32_t num_sge,
|
||||
uint8_t sgid_idx, union ibv_gid *sgid,
|
||||
union ibv_gid *dgid, uint32_t dqpn, uint32_t dqkey,
|
||||
void *ctx);
|
||||
void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#ifndef RDMA_BACKEND_DEFS_H
|
||||
#define RDMA_BACKEND_DEFS_H
|
||||
|
||||
#include <infiniband/verbs.h>
|
||||
#include "qemu/thread.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include <infiniband/verbs.h>
|
||||
#include "contrib/rdmacm-mux/rdmacm-mux.h"
|
||||
|
||||
typedef struct RdmaDeviceResources RdmaDeviceResources;
|
||||
|
||||
@@ -28,17 +30,27 @@ typedef struct RdmaBackendThread {
|
||||
bool is_running; /* Set by the thread to report its status */
|
||||
} RdmaBackendThread;
|
||||
|
||||
typedef struct RecvMadList {
|
||||
QemuMutex lock;
|
||||
QList *list;
|
||||
} RecvMadList;
|
||||
|
||||
typedef struct RdmaCmMux {
|
||||
CharBackend *chr_be;
|
||||
int can_receive;
|
||||
} RdmaCmMux;
|
||||
|
||||
typedef struct RdmaBackendDev {
|
||||
struct ibv_device_attr dev_attr;
|
||||
RdmaBackendThread comp_thread;
|
||||
union ibv_gid gid;
|
||||
PCIDevice *dev;
|
||||
RdmaDeviceResources *rdma_dev_res;
|
||||
struct ibv_device *ib_dev;
|
||||
struct ibv_context *context;
|
||||
struct ibv_comp_channel *channel;
|
||||
uint8_t port_num;
|
||||
uint8_t backend_gid_idx;
|
||||
RecvMadList recv_mads_list;
|
||||
RdmaCmMux rdmacm_mux;
|
||||
} RdmaBackendDev;
|
||||
|
||||
typedef struct RdmaBackendPD {
|
||||
@@ -58,6 +70,7 @@ typedef struct RdmaBackendCQ {
|
||||
typedef struct RdmaBackendQP {
|
||||
struct ibv_pd *ibpd;
|
||||
struct ibv_qp *ibqp;
|
||||
uint8_t sgid_idx;
|
||||
} RdmaBackendQP;
|
||||
|
||||
#endif
|
||||
|
||||
+113
-7
@@ -43,7 +43,7 @@ static inline void res_tbl_free(RdmaRmResTbl *tbl)
|
||||
{
|
||||
qemu_mutex_destroy(&tbl->lock);
|
||||
g_free(tbl->tbl);
|
||||
bitmap_zero_extend(tbl->bitmap, tbl->tbl_sz, 0);
|
||||
g_free(tbl->bitmap);
|
||||
}
|
||||
|
||||
static inline void *res_tbl_get(RdmaRmResTbl *tbl, uint32_t handle)
|
||||
@@ -263,7 +263,7 @@ int rdma_rm_alloc_cq(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
}
|
||||
|
||||
cq->opaque = opaque;
|
||||
cq->notify = false;
|
||||
cq->notify = CNT_CLEAR;
|
||||
|
||||
rc = rdma_backend_create_cq(backend_dev, &cq->backend_cq, cqe);
|
||||
if (rc) {
|
||||
@@ -291,7 +291,10 @@ void rdma_rm_req_notify_cq(RdmaDeviceResources *dev_res, uint32_t cq_handle,
|
||||
return;
|
||||
}
|
||||
|
||||
cq->notify = notify;
|
||||
if (cq->notify != CNT_SET) {
|
||||
cq->notify = notify ? CNT_ARM : CNT_CLEAR;
|
||||
}
|
||||
|
||||
pr_dbg("notify=%d\n", cq->notify);
|
||||
}
|
||||
|
||||
@@ -349,6 +352,11 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (qp_type == IBV_QPT_GSI) {
|
||||
scq->notify = CNT_SET;
|
||||
rcq->notify = CNT_SET;
|
||||
}
|
||||
|
||||
qp = res_tbl_alloc(&dev_res->qp_tbl, &rm_qpn);
|
||||
if (!qp) {
|
||||
return -ENOMEM;
|
||||
@@ -383,7 +391,7 @@ out_dealloc_qp:
|
||||
}
|
||||
|
||||
int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
uint32_t qp_handle, uint32_t attr_mask,
|
||||
uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
|
||||
union ibv_gid *dgid, uint32_t dqpn,
|
||||
enum ibv_qp_state qp_state, uint32_t qkey,
|
||||
uint32_t rq_psn, uint32_t sq_psn)
|
||||
@@ -392,6 +400,7 @@ int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
int ret;
|
||||
|
||||
pr_dbg("qpn=0x%x\n", qp_handle);
|
||||
pr_dbg("qkey=0x%x\n", qkey);
|
||||
|
||||
qp = rdma_rm_get_qp(dev_res, qp_handle);
|
||||
if (!qp) {
|
||||
@@ -422,9 +431,19 @@ int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
}
|
||||
|
||||
if (qp->qp_state == IBV_QPS_RTR) {
|
||||
/* Get backend gid index */
|
||||
pr_dbg("Guest sgid_idx=%d\n", sgid_idx);
|
||||
sgid_idx = rdma_rm_get_backend_gid_index(dev_res, backend_dev,
|
||||
sgid_idx);
|
||||
if (sgid_idx <= 0) { /* TODO check also less than bk.max_sgid */
|
||||
pr_dbg("Fail to get bk sgid_idx for sgid_idx %d\n", sgid_idx);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = rdma_backend_qp_state_rtr(backend_dev, &qp->backend_qp,
|
||||
qp->qp_type, dgid, dqpn, rq_psn,
|
||||
qkey, attr_mask & IBV_QP_QKEY);
|
||||
qp->qp_type, sgid_idx, dgid, dqpn,
|
||||
rq_psn, qkey,
|
||||
attr_mask & IBV_QP_QKEY);
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
}
|
||||
@@ -515,11 +534,93 @@ void rdma_rm_dealloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id)
|
||||
res_tbl_dealloc(&dev_res->cqe_ctx_tbl, cqe_ctx_id);
|
||||
}
|
||||
|
||||
int rdma_rm_add_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname, union ibv_gid *gid, int gid_idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = rdma_backend_add_gid(backend_dev, ifname, gid);
|
||||
if (rc) {
|
||||
pr_dbg("Fail to add gid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&dev_res->port.gid_tbl[gid_idx].gid, gid, sizeof(*gid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rdma_rm_del_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname, int gid_idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!dev_res->port.gid_tbl[gid_idx].gid.global.interface_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = rdma_backend_del_gid(backend_dev, ifname,
|
||||
&dev_res->port.gid_tbl[gid_idx].gid);
|
||||
if (rc) {
|
||||
pr_dbg("Fail to delete gid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(dev_res->port.gid_tbl[gid_idx].gid.raw, 0,
|
||||
sizeof(dev_res->port.gid_tbl[gid_idx].gid));
|
||||
dev_res->port.gid_tbl[gid_idx].backend_gid_index = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rdma_rm_get_backend_gid_index(RdmaDeviceResources *dev_res,
|
||||
RdmaBackendDev *backend_dev, int sgid_idx)
|
||||
{
|
||||
if (unlikely(sgid_idx < 0 || sgid_idx > MAX_PORT_GIDS)) {
|
||||
pr_dbg("Got invalid sgid_idx %d\n", sgid_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(dev_res->port.gid_tbl[sgid_idx].backend_gid_index == -1)) {
|
||||
dev_res->port.gid_tbl[sgid_idx].backend_gid_index =
|
||||
rdma_backend_get_gid_index(backend_dev,
|
||||
&dev_res->port.gid_tbl[sgid_idx].gid);
|
||||
}
|
||||
|
||||
pr_dbg("backend_gid_index=%d\n",
|
||||
dev_res->port.gid_tbl[sgid_idx].backend_gid_index);
|
||||
|
||||
return dev_res->port.gid_tbl[sgid_idx].backend_gid_index;
|
||||
}
|
||||
|
||||
static void destroy_qp_hash_key(gpointer data)
|
||||
{
|
||||
g_bytes_unref(data);
|
||||
}
|
||||
|
||||
static void init_ports(RdmaDeviceResources *dev_res)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&dev_res->port, 0, sizeof(dev_res->port));
|
||||
|
||||
dev_res->port.state = IBV_PORT_DOWN;
|
||||
for (i = 0; i < MAX_PORT_GIDS; i++) {
|
||||
dev_res->port.gid_tbl[i].backend_gid_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void fini_ports(RdmaDeviceResources *dev_res,
|
||||
RdmaBackendDev *backend_dev, const char *ifname)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev_res->port.state = IBV_PORT_DOWN;
|
||||
for (i = 0; i < MAX_PORT_GIDS; i++) {
|
||||
rdma_rm_del_gid(dev_res, backend_dev, ifname, i);
|
||||
}
|
||||
}
|
||||
|
||||
int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -537,11 +638,16 @@ int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
|
||||
dev_attr->max_qp_wr, sizeof(void *));
|
||||
res_tbl_init("UC", &dev_res->uc_tbl, MAX_UCS, sizeof(RdmaRmUC));
|
||||
|
||||
init_ports(dev_res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rdma_rm_fini(RdmaDeviceResources *dev_res)
|
||||
void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname)
|
||||
{
|
||||
fini_ports(dev_res, backend_dev, ifname);
|
||||
|
||||
res_tbl_free(&dev_res->uc_tbl);
|
||||
res_tbl_free(&dev_res->cqe_ctx_tbl);
|
||||
res_tbl_free(&dev_res->qp_tbl);
|
||||
|
||||
+15
-2
@@ -22,7 +22,8 @@
|
||||
|
||||
int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
|
||||
Error **errp);
|
||||
void rdma_rm_fini(RdmaDeviceResources *dev_res);
|
||||
void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname);
|
||||
|
||||
int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
uint32_t *pd_handle, uint32_t ctx_handle);
|
||||
@@ -55,7 +56,7 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
|
||||
uint32_t recv_cq_handle, void *opaque, uint32_t *qpn);
|
||||
RdmaRmQP *rdma_rm_get_qp(RdmaDeviceResources *dev_res, uint32_t qpn);
|
||||
int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
uint32_t qp_handle, uint32_t attr_mask,
|
||||
uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
|
||||
union ibv_gid *dgid, uint32_t dqpn,
|
||||
enum ibv_qp_state qp_state, uint32_t qkey,
|
||||
uint32_t rq_psn, uint32_t sq_psn);
|
||||
@@ -69,4 +70,16 @@ int rdma_rm_alloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t *cqe_ctx_id,
|
||||
void *rdma_rm_get_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id);
|
||||
void rdma_rm_dealloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id);
|
||||
|
||||
int rdma_rm_add_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname, union ibv_gid *gid, int gid_idx);
|
||||
int rdma_rm_del_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
|
||||
const char *ifname, int gid_idx);
|
||||
int rdma_rm_get_backend_gid_index(RdmaDeviceResources *dev_res,
|
||||
RdmaBackendDev *backend_dev, int sgid_idx);
|
||||
static inline union ibv_gid *rdma_rm_get_gid(RdmaDeviceResources *dev_res,
|
||||
int sgid_idx)
|
||||
{
|
||||
return &dev_res->port.gid_tbl[sgid_idx].gid;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+16
-5
@@ -18,8 +18,8 @@
|
||||
|
||||
#include "rdma_backend_defs.h"
|
||||
|
||||
#define MAX_PORTS 1
|
||||
#define MAX_PORT_GIDS 1
|
||||
#define MAX_PORTS 1 /* Do not change - we support only one port */
|
||||
#define MAX_PORT_GIDS 255
|
||||
#define MAX_GIDS MAX_PORT_GIDS
|
||||
#define MAX_PORT_PKEYS 1
|
||||
#define MAX_PKEYS MAX_PORT_PKEYS
|
||||
@@ -49,10 +49,16 @@ typedef struct RdmaRmPD {
|
||||
uint32_t ctx_handle;
|
||||
} RdmaRmPD;
|
||||
|
||||
typedef enum CQNotificationType {
|
||||
CNT_CLEAR,
|
||||
CNT_ARM,
|
||||
CNT_SET,
|
||||
} CQNotificationType;
|
||||
|
||||
typedef struct RdmaRmCQ {
|
||||
RdmaBackendCQ backend_cq;
|
||||
void *opaque;
|
||||
bool notify;
|
||||
CQNotificationType notify;
|
||||
} RdmaRmCQ;
|
||||
|
||||
/* MR (DMA region) */
|
||||
@@ -80,13 +86,18 @@ typedef struct RdmaRmQP {
|
||||
enum ibv_qp_state qp_state;
|
||||
} RdmaRmQP;
|
||||
|
||||
typedef struct RdmaRmGid {
|
||||
union ibv_gid gid;
|
||||
int backend_gid_index;
|
||||
} RdmaRmGid;
|
||||
|
||||
typedef struct RdmaRmPort {
|
||||
union ibv_gid gid_tbl[MAX_PORT_GIDS];
|
||||
RdmaRmGid gid_tbl[MAX_PORT_GIDS];
|
||||
enum ibv_port_state state;
|
||||
} RdmaRmPort;
|
||||
|
||||
typedef struct RdmaDeviceResources {
|
||||
RdmaRmPort ports[MAX_PORTS];
|
||||
RdmaRmPort port;
|
||||
RdmaRmResTbl pd_tbl;
|
||||
RdmaRmResTbl mr_tbl;
|
||||
RdmaRmResTbl uc_tbl;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#define pr_info(fmt, ...) \
|
||||
fprintf(stdout, "%s: %-20s (%3d): " fmt, "rdma", __func__, __LINE__,\
|
||||
@@ -39,12 +40,36 @@ extern unsigned long pr_dbg_cnt;
|
||||
#define pr_dbg(fmt, ...) \
|
||||
fprintf(stdout, "%lx %ld: %-20s (%3d): " fmt, pthread_self(), pr_dbg_cnt++, \
|
||||
__func__, __LINE__, ## __VA_ARGS__)
|
||||
|
||||
#define pr_dbg_buf(title, buf, len) \
|
||||
{ \
|
||||
int i; \
|
||||
char *b = g_malloc0(len * 3 + 1); \
|
||||
char b1[4]; \
|
||||
for (i = 0; i < len; i++) { \
|
||||
sprintf(b1, "%.2X ", buf[i] & 0x000000FF); \
|
||||
strcat(b, b1); \
|
||||
} \
|
||||
pr_dbg("%s (%d): %s\n", title, len, b); \
|
||||
g_free(b); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define init_pr_dbg(void)
|
||||
#define pr_dbg(fmt, ...)
|
||||
#define pr_dbg_buf(title, buf, len)
|
||||
#endif
|
||||
|
||||
void *rdma_pci_dma_map(PCIDevice *dev, dma_addr_t addr, dma_addr_t plen);
|
||||
void rdma_pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len);
|
||||
|
||||
static inline void addrconf_addr_eui48(uint8_t *eui, const char *addr)
|
||||
{
|
||||
memcpy(eui, addr, 3);
|
||||
eui[3] = 0xFF;
|
||||
eui[4] = 0xFE;
|
||||
memcpy(eui + 5, addr + 3, 3);
|
||||
eui[0] ^= 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
#define PVRDMA_PVRDMA_H
|
||||
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/msix.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/net/vmxnet3_defs.h"
|
||||
|
||||
#include "../rdma_backend_defs.h"
|
||||
#include "../rdma_rm_defs.h"
|
||||
@@ -51,7 +54,7 @@
|
||||
#define PVRDMA_FW_VERSION 14
|
||||
|
||||
/* Some defaults */
|
||||
#define PVRDMA_PKEY 0x7FFF
|
||||
#define PVRDMA_PKEY 0xFFFF
|
||||
|
||||
typedef struct DSRInfo {
|
||||
dma_addr_t dma;
|
||||
@@ -78,11 +81,14 @@ typedef struct PVRDMADev {
|
||||
int interrupt_mask;
|
||||
struct ibv_device_attr dev_attr;
|
||||
uint64_t node_guid;
|
||||
char *backend_eth_device_name;
|
||||
char *backend_device_name;
|
||||
uint8_t backend_gid_idx;
|
||||
uint8_t backend_port_num;
|
||||
RdmaBackendDev backend_dev;
|
||||
RdmaDeviceResources rdma_dev_res;
|
||||
CharBackend mad_chr;
|
||||
VMXNET3State *func0;
|
||||
Notifier shutdown_notifier;
|
||||
} PVRDMADev;
|
||||
#define PVRDMA_DEV(dev) OBJECT_CHECK(PVRDMADev, (dev), PVRDMA_HW_NAME)
|
||||
|
||||
|
||||
+141
-128
@@ -128,6 +128,9 @@ static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
struct pvrdma_port_attr attrs = {0};
|
||||
|
||||
pr_dbg("port=%d\n", cmd->port_num);
|
||||
if (cmd->port_num > MAX_PORTS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rdma_backend_query_port(&dev->backend_dev,
|
||||
(struct ibv_port_attr *)&attrs)) {
|
||||
@@ -135,11 +138,9 @@ static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
}
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_QUERY_PORT_RESP;
|
||||
resp->hdr.err = 0;
|
||||
|
||||
resp->attrs.state = attrs.state;
|
||||
resp->attrs.state = dev->func0->device_active ? attrs.state :
|
||||
PVRDMA_PORT_DOWN;
|
||||
resp->attrs.max_mtu = attrs.max_mtu;
|
||||
resp->attrs.active_mtu = attrs.active_mtu;
|
||||
resp->attrs.phys_state = attrs.phys_state;
|
||||
@@ -159,12 +160,16 @@ static int query_pkey(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
struct pvrdma_cmd_query_pkey_resp *resp = &rsp->query_pkey_resp;
|
||||
|
||||
pr_dbg("port=%d\n", cmd->port_num);
|
||||
if (cmd->port_num > MAX_PORTS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_dbg("index=%d\n", cmd->index);
|
||||
if (cmd->index > MAX_PKEYS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_QUERY_PKEY_RESP;
|
||||
resp->hdr.err = 0;
|
||||
|
||||
resp->pkey = PVRDMA_PKEY;
|
||||
pr_dbg("pkey=0x%x\n", resp->pkey);
|
||||
@@ -177,17 +182,15 @@ static int create_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
{
|
||||
struct pvrdma_cmd_create_pd *cmd = &req->create_pd;
|
||||
struct pvrdma_cmd_create_pd_resp *resp = &rsp->create_pd_resp;
|
||||
int rc;
|
||||
|
||||
pr_dbg("context=0x%x\n", cmd->ctx_handle ? cmd->ctx_handle : 0);
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_CREATE_PD_RESP;
|
||||
resp->hdr.err = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
&resp->pd_handle, cmd->ctx_handle);
|
||||
rc = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
&resp->pd_handle, cmd->ctx_handle);
|
||||
|
||||
pr_dbg("ret=%d\n", resp->hdr.err);
|
||||
return resp->hdr.err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -209,10 +212,9 @@ static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
struct pvrdma_cmd_create_mr_resp *resp = &rsp->create_mr_resp;
|
||||
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||
void *host_virt = NULL;
|
||||
int rc = 0;
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_CREATE_MR_RESP;
|
||||
|
||||
pr_dbg("pd_handle=%d\n", cmd->pd_handle);
|
||||
pr_dbg("access_flags=0x%x\n", cmd->access_flags);
|
||||
@@ -223,22 +225,18 @@ static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
cmd->length);
|
||||
if (!host_virt) {
|
||||
pr_dbg("Failed to map to pdir\n");
|
||||
resp->hdr.err = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
resp->hdr.err = rdma_rm_alloc_mr(&dev->rdma_dev_res, cmd->pd_handle,
|
||||
cmd->start, cmd->length, host_virt,
|
||||
cmd->access_flags, &resp->mr_handle,
|
||||
&resp->lkey, &resp->rkey);
|
||||
if (host_virt && !resp->hdr.err) {
|
||||
rc = rdma_rm_alloc_mr(&dev->rdma_dev_res, cmd->pd_handle, cmd->start,
|
||||
cmd->length, host_virt, cmd->access_flags,
|
||||
&resp->mr_handle, &resp->lkey, &resp->rkey);
|
||||
if (rc && host_virt) {
|
||||
munmap(host_virt, cmd->length);
|
||||
}
|
||||
|
||||
out:
|
||||
pr_dbg("ret=%d\n", resp->hdr.err);
|
||||
return resp->hdr.err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -261,6 +259,11 @@ static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring,
|
||||
int rc = -EINVAL;
|
||||
char ring_name[MAX_RING_NAME_SZ];
|
||||
|
||||
if (!nchunks || nchunks > PVRDMA_MAX_FAST_REG_PAGES) {
|
||||
pr_dbg("invalid nchunks: %d\n", nchunks);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_dbg("pdir_dma=0x%llx\n", (long long unsigned int)pdir_dma);
|
||||
dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
|
||||
if (!dir) {
|
||||
@@ -310,34 +313,43 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void destroy_cq_ring(PvrdmaRing *ring)
|
||||
{
|
||||
pvrdma_ring_free(ring);
|
||||
/* ring_state was in slot 1, not 0 so need to jump back */
|
||||
rdma_pci_dma_unmap(ring->dev, --ring->ring_state, TARGET_PAGE_SIZE);
|
||||
g_free(ring);
|
||||
}
|
||||
|
||||
static int create_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp)
|
||||
{
|
||||
struct pvrdma_cmd_create_cq *cmd = &req->create_cq;
|
||||
struct pvrdma_cmd_create_cq_resp *resp = &rsp->create_cq_resp;
|
||||
PvrdmaRing *ring = NULL;
|
||||
int rc;
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_CREATE_CQ_RESP;
|
||||
|
||||
resp->cqe = cmd->cqe;
|
||||
|
||||
resp->hdr.err = create_cq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma,
|
||||
cmd->nchunks, cmd->cqe);
|
||||
if (resp->hdr.err) {
|
||||
goto out;
|
||||
rc = create_cq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma, cmd->nchunks,
|
||||
cmd->cqe);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_dbg("ring=%p\n", ring);
|
||||
|
||||
resp->hdr.err = rdma_rm_alloc_cq(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
cmd->cqe, &resp->cq_handle, ring);
|
||||
rc = rdma_rm_alloc_cq(&dev->rdma_dev_res, &dev->backend_dev, cmd->cqe,
|
||||
&resp->cq_handle, ring);
|
||||
if (rc) {
|
||||
destroy_cq_ring(ring);
|
||||
}
|
||||
|
||||
resp->cqe = cmd->cqe;
|
||||
|
||||
out:
|
||||
pr_dbg("ret=%d\n", resp->hdr.err);
|
||||
return resp->hdr.err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -356,10 +368,7 @@ static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
}
|
||||
|
||||
ring = (PvrdmaRing *)cq->opaque;
|
||||
pvrdma_ring_free(ring);
|
||||
/* ring_state was in slot 1, not 0 so need to jump back */
|
||||
rdma_pci_dma_unmap(PCI_DEVICE(dev), --ring->ring_state, TARGET_PAGE_SIZE);
|
||||
g_free(ring);
|
||||
destroy_cq_ring(ring);
|
||||
|
||||
rdma_rm_dealloc_cq(&dev->rdma_dev_res, cmd->cq_handle);
|
||||
|
||||
@@ -377,6 +386,12 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
|
||||
char ring_name[MAX_RING_NAME_SZ];
|
||||
uint32_t wqe_sz;
|
||||
|
||||
if (!spages || spages > PVRDMA_MAX_FAST_REG_PAGES
|
||||
|| !rpages || rpages > PVRDMA_MAX_FAST_REG_PAGES) {
|
||||
pr_dbg("invalid pages: %d, %d\n", spages, rpages);
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_dbg("pdir_dma=0x%llx\n", (long long unsigned int)pdir_dma);
|
||||
dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
|
||||
if (!dir) {
|
||||
@@ -451,36 +466,49 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void destroy_qp_rings(PvrdmaRing *ring)
|
||||
{
|
||||
pr_dbg("sring=%p\n", &ring[0]);
|
||||
pvrdma_ring_free(&ring[0]);
|
||||
pr_dbg("rring=%p\n", &ring[1]);
|
||||
pvrdma_ring_free(&ring[1]);
|
||||
|
||||
rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
|
||||
g_free(ring);
|
||||
}
|
||||
|
||||
static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp)
|
||||
{
|
||||
struct pvrdma_cmd_create_qp *cmd = &req->create_qp;
|
||||
struct pvrdma_cmd_create_qp_resp *resp = &rsp->create_qp_resp;
|
||||
PvrdmaRing *rings = NULL;
|
||||
int rc;
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_CREATE_QP_RESP;
|
||||
|
||||
pr_dbg("total_chunks=%d\n", cmd->total_chunks);
|
||||
pr_dbg("send_chunks=%d\n", cmd->send_chunks);
|
||||
|
||||
resp->hdr.err = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
|
||||
cmd->max_send_wr, cmd->max_send_sge,
|
||||
cmd->send_chunks, cmd->max_recv_wr,
|
||||
cmd->max_recv_sge, cmd->total_chunks -
|
||||
cmd->send_chunks - 1);
|
||||
if (resp->hdr.err) {
|
||||
goto out;
|
||||
rc = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
|
||||
cmd->max_send_wr, cmd->max_send_sge, cmd->send_chunks,
|
||||
cmd->max_recv_wr, cmd->max_recv_sge,
|
||||
cmd->total_chunks - cmd->send_chunks - 1);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_dbg("rings=%p\n", rings);
|
||||
|
||||
resp->hdr.err = rdma_rm_alloc_qp(&dev->rdma_dev_res, cmd->pd_handle,
|
||||
cmd->qp_type, cmd->max_send_wr,
|
||||
cmd->max_send_sge, cmd->send_cq_handle,
|
||||
cmd->max_recv_wr, cmd->max_recv_sge,
|
||||
cmd->recv_cq_handle, rings, &resp->qpn);
|
||||
rc = rdma_rm_alloc_qp(&dev->rdma_dev_res, cmd->pd_handle, cmd->qp_type,
|
||||
cmd->max_send_wr, cmd->max_send_sge,
|
||||
cmd->send_cq_handle, cmd->max_recv_wr,
|
||||
cmd->max_recv_sge, cmd->recv_cq_handle, rings,
|
||||
&resp->qpn);
|
||||
if (rc) {
|
||||
destroy_qp_rings(rings);
|
||||
return rc;
|
||||
}
|
||||
|
||||
resp->max_send_wr = cmd->max_send_wr;
|
||||
resp->max_recv_wr = cmd->max_recv_wr;
|
||||
@@ -488,32 +516,31 @@ static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
resp->max_recv_sge = cmd->max_recv_sge;
|
||||
resp->max_inline_data = cmd->max_inline_data;
|
||||
|
||||
out:
|
||||
pr_dbg("ret=%d\n", resp->hdr.err);
|
||||
return resp->hdr.err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int modify_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp)
|
||||
{
|
||||
struct pvrdma_cmd_modify_qp *cmd = &req->modify_qp;
|
||||
int rc;
|
||||
|
||||
pr_dbg("qp_handle=%d\n", cmd->qp_handle);
|
||||
|
||||
memset(rsp, 0, sizeof(*rsp));
|
||||
rsp->hdr.response = cmd->hdr.response;
|
||||
rsp->hdr.ack = PVRDMA_CMD_MODIFY_QP_RESP;
|
||||
|
||||
rsp->hdr.err = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
cmd->qp_handle, cmd->attr_mask,
|
||||
(union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid,
|
||||
cmd->attrs.dest_qp_num,
|
||||
(enum ibv_qp_state)cmd->attrs.qp_state,
|
||||
cmd->attrs.qkey, cmd->attrs.rq_psn,
|
||||
cmd->attrs.sq_psn);
|
||||
/* No need to verify sgid_index since it is u8 */
|
||||
|
||||
pr_dbg("ret=%d\n", rsp->hdr.err);
|
||||
return rsp->hdr.err;
|
||||
rc = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
cmd->qp_handle, cmd->attr_mask,
|
||||
cmd->attrs.ah_attr.grh.sgid_index,
|
||||
(union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid,
|
||||
cmd->attrs.dest_qp_num,
|
||||
(enum ibv_qp_state)cmd->attrs.qp_state,
|
||||
cmd->attrs.qkey, cmd->attrs.rq_psn,
|
||||
cmd->attrs.sq_psn);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -522,21 +549,18 @@ static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
struct pvrdma_cmd_query_qp *cmd = &req->query_qp;
|
||||
struct pvrdma_cmd_query_qp_resp *resp = &rsp->query_qp_resp;
|
||||
struct ibv_qp_init_attr init_attr;
|
||||
int rc;
|
||||
|
||||
pr_dbg("qp_handle=%d\n", cmd->qp_handle);
|
||||
pr_dbg("attr_mask=0x%x\n", cmd->attr_mask);
|
||||
|
||||
memset(rsp, 0, sizeof(*rsp));
|
||||
rsp->hdr.response = cmd->hdr.response;
|
||||
rsp->hdr.ack = PVRDMA_CMD_QUERY_QP_RESP;
|
||||
|
||||
rsp->hdr.err = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
cmd->qp_handle,
|
||||
(struct ibv_qp_attr *)&resp->attrs,
|
||||
cmd->attr_mask, &init_attr);
|
||||
rc = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev, cmd->qp_handle,
|
||||
(struct ibv_qp_attr *)&resp->attrs, cmd->attr_mask,
|
||||
&init_attr);
|
||||
|
||||
pr_dbg("ret=%d\n", rsp->hdr.err);
|
||||
return rsp->hdr.err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -555,13 +579,7 @@ static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
rdma_rm_dealloc_qp(&dev->rdma_dev_res, cmd->qp_handle);
|
||||
|
||||
ring = (PvrdmaRing *)qp->opaque;
|
||||
pr_dbg("sring=%p\n", &ring[0]);
|
||||
pvrdma_ring_free(&ring[0]);
|
||||
pr_dbg("rring=%p\n", &ring[1]);
|
||||
pvrdma_ring_free(&ring[1]);
|
||||
|
||||
rdma_pci_dma_unmap(PCI_DEVICE(dev), ring->ring_state, TARGET_PAGE_SIZE);
|
||||
g_free(ring);
|
||||
destroy_qp_rings(ring);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -570,10 +588,8 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp)
|
||||
{
|
||||
struct pvrdma_cmd_create_bind *cmd = &req->create_bind;
|
||||
#ifdef PVRDMA_DEBUG
|
||||
__be64 *subnet = (__be64 *)&cmd->new_gid[0];
|
||||
__be64 *if_id = (__be64 *)&cmd->new_gid[8];
|
||||
#endif
|
||||
int rc;
|
||||
union ibv_gid *gid = (union ibv_gid *)&cmd->new_gid;
|
||||
|
||||
pr_dbg("index=%d\n", cmd->index);
|
||||
|
||||
@@ -582,26 +598,20 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
}
|
||||
|
||||
pr_dbg("gid[%d]=0x%llx,0x%llx\n", cmd->index,
|
||||
(long long unsigned int)be64_to_cpu(*subnet),
|
||||
(long long unsigned int)be64_to_cpu(*if_id));
|
||||
(long long unsigned int)be64_to_cpu(gid->global.subnet_prefix),
|
||||
(long long unsigned int)be64_to_cpu(gid->global.interface_id));
|
||||
|
||||
/* Driver forces to one port only */
|
||||
memcpy(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw, &cmd->new_gid,
|
||||
sizeof(cmd->new_gid));
|
||||
rc = rdma_rm_add_gid(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
dev->backend_eth_device_name, gid, cmd->index);
|
||||
|
||||
/* TODO: Since drivers stores node_guid at load_dsr phase then this
|
||||
* assignment is not relevant, i need to figure out a way how to
|
||||
* retrieve MAC of our netdev */
|
||||
dev->node_guid = dev->rdma_dev_res.ports[0].gid_tbl[0].global.interface_id;
|
||||
pr_dbg("dev->node_guid=0x%llx\n",
|
||||
(long long unsigned int)be64_to_cpu(dev->node_guid));
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct pvrdma_cmd_destroy_bind *cmd = &req->destroy_bind;
|
||||
|
||||
pr_dbg("index=%d\n", cmd->index);
|
||||
@@ -610,10 +620,10 @@ static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw, 0,
|
||||
sizeof(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw));
|
||||
rc = rdma_rm_del_gid(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
dev->backend_eth_device_name, cmd->index);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -621,18 +631,14 @@ static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
{
|
||||
struct pvrdma_cmd_create_uc *cmd = &req->create_uc;
|
||||
struct pvrdma_cmd_create_uc_resp *resp = &rsp->create_uc_resp;
|
||||
int rc;
|
||||
|
||||
pr_dbg("pfn=%d\n", cmd->pfn);
|
||||
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->hdr.response = cmd->hdr.response;
|
||||
resp->hdr.ack = PVRDMA_CMD_CREATE_UC_RESP;
|
||||
resp->hdr.err = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn,
|
||||
&resp->ctx_handle);
|
||||
rc = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn, &resp->ctx_handle);
|
||||
|
||||
pr_dbg("ret=%d\n", resp->hdr.err);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
@@ -646,30 +652,32 @@ static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cmd_handler {
|
||||
uint32_t cmd;
|
||||
uint32_t ack;
|
||||
int (*exec)(PVRDMADev *dev, union pvrdma_cmd_req *req,
|
||||
union pvrdma_cmd_resp *rsp);
|
||||
};
|
||||
|
||||
static struct cmd_handler cmd_handlers[] = {
|
||||
{PVRDMA_CMD_QUERY_PORT, query_port},
|
||||
{PVRDMA_CMD_QUERY_PKEY, query_pkey},
|
||||
{PVRDMA_CMD_CREATE_PD, create_pd},
|
||||
{PVRDMA_CMD_DESTROY_PD, destroy_pd},
|
||||
{PVRDMA_CMD_CREATE_MR, create_mr},
|
||||
{PVRDMA_CMD_DESTROY_MR, destroy_mr},
|
||||
{PVRDMA_CMD_CREATE_CQ, create_cq},
|
||||
{PVRDMA_CMD_RESIZE_CQ, NULL},
|
||||
{PVRDMA_CMD_DESTROY_CQ, destroy_cq},
|
||||
{PVRDMA_CMD_CREATE_QP, create_qp},
|
||||
{PVRDMA_CMD_MODIFY_QP, modify_qp},
|
||||
{PVRDMA_CMD_QUERY_QP, query_qp},
|
||||
{PVRDMA_CMD_DESTROY_QP, destroy_qp},
|
||||
{PVRDMA_CMD_CREATE_UC, create_uc},
|
||||
{PVRDMA_CMD_DESTROY_UC, destroy_uc},
|
||||
{PVRDMA_CMD_CREATE_BIND, create_bind},
|
||||
{PVRDMA_CMD_DESTROY_BIND, destroy_bind},
|
||||
{PVRDMA_CMD_QUERY_PORT, PVRDMA_CMD_QUERY_PORT_RESP, query_port},
|
||||
{PVRDMA_CMD_QUERY_PKEY, PVRDMA_CMD_QUERY_PKEY_RESP, query_pkey},
|
||||
{PVRDMA_CMD_CREATE_PD, PVRDMA_CMD_CREATE_PD_RESP, create_pd},
|
||||
{PVRDMA_CMD_DESTROY_PD, PVRDMA_CMD_DESTROY_PD_RESP_NOOP, destroy_pd},
|
||||
{PVRDMA_CMD_CREATE_MR, PVRDMA_CMD_CREATE_MR_RESP, create_mr},
|
||||
{PVRDMA_CMD_DESTROY_MR, PVRDMA_CMD_DESTROY_MR_RESP_NOOP, destroy_mr},
|
||||
{PVRDMA_CMD_CREATE_CQ, PVRDMA_CMD_CREATE_CQ_RESP, create_cq},
|
||||
{PVRDMA_CMD_RESIZE_CQ, PVRDMA_CMD_RESIZE_CQ_RESP, NULL},
|
||||
{PVRDMA_CMD_DESTROY_CQ, PVRDMA_CMD_DESTROY_CQ_RESP_NOOP, destroy_cq},
|
||||
{PVRDMA_CMD_CREATE_QP, PVRDMA_CMD_CREATE_QP_RESP, create_qp},
|
||||
{PVRDMA_CMD_MODIFY_QP, PVRDMA_CMD_MODIFY_QP_RESP, modify_qp},
|
||||
{PVRDMA_CMD_QUERY_QP, PVRDMA_CMD_QUERY_QP_RESP, query_qp},
|
||||
{PVRDMA_CMD_DESTROY_QP, PVRDMA_CMD_DESTROY_QP_RESP, destroy_qp},
|
||||
{PVRDMA_CMD_CREATE_UC, PVRDMA_CMD_CREATE_UC_RESP, create_uc},
|
||||
{PVRDMA_CMD_DESTROY_UC, PVRDMA_CMD_DESTROY_UC_RESP_NOOP, destroy_uc},
|
||||
{PVRDMA_CMD_CREATE_BIND, PVRDMA_CMD_CREATE_BIND_RESP_NOOP, create_bind},
|
||||
{PVRDMA_CMD_DESTROY_BIND, PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, destroy_bind},
|
||||
};
|
||||
|
||||
int execute_command(PVRDMADev *dev)
|
||||
@@ -692,7 +700,12 @@ int execute_command(PVRDMADev *dev)
|
||||
}
|
||||
|
||||
err = cmd_handlers[dsr_info->req->hdr.cmd].exec(dev, dsr_info->req,
|
||||
dsr_info->rsp);
|
||||
dsr_info->rsp);
|
||||
dsr_info->rsp->hdr.response = dsr_info->req->hdr.response;
|
||||
dsr_info->rsp->hdr.ack = cmd_handlers[dsr_info->req->hdr.cmd].ack;
|
||||
dsr_info->rsp->hdr.err = err < 0 ? -err : 0;
|
||||
pr_dbg("rsp->hdr.err=%d\n", dsr_info->rsp->hdr.err);
|
||||
|
||||
out:
|
||||
set_reg_val(dev, PVRDMA_REG_ERR, err);
|
||||
post_interrupt(dev, INTR_VEC_CMD_RING);
|
||||
|
||||
@@ -73,23 +73,16 @@ out:
|
||||
|
||||
void *pvrdma_ring_next_elem_read(PvrdmaRing *ring)
|
||||
{
|
||||
int e;
|
||||
unsigned int idx = 0, offset;
|
||||
|
||||
/*
|
||||
pr_dbg("%s: t=%d, h=%d\n", ring->name, ring->ring_state->prod_tail,
|
||||
ring->ring_state->cons_head);
|
||||
*/
|
||||
|
||||
if (!pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx)) {
|
||||
e = pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx);
|
||||
if (e <= 0) {
|
||||
pr_dbg("No more data in ring\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = idx * ring->elem_sz;
|
||||
/*
|
||||
pr_dbg("idx=%d\n", idx);
|
||||
pr_dbg("offset=%d\n", offset);
|
||||
*/
|
||||
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -105,20 +98,20 @@ void pvrdma_ring_read_inc(PvrdmaRing *ring)
|
||||
|
||||
void *pvrdma_ring_next_elem_write(PvrdmaRing *ring)
|
||||
{
|
||||
unsigned int idx, offset, tail;
|
||||
int idx;
|
||||
unsigned int offset, tail;
|
||||
|
||||
/*
|
||||
pr_dbg("%s: t=%d, h=%d\n", ring->name, ring->ring_state->prod_tail,
|
||||
ring->ring_state->cons_head);
|
||||
*/
|
||||
|
||||
if (!pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail)) {
|
||||
idx = pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail);
|
||||
if (idx <= 0) {
|
||||
pr_dbg("CQ is full\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = pvrdma_idx(&ring->ring_state->prod_tail, ring->max_elems);
|
||||
/* TODO: tail == idx */
|
||||
if (idx < 0 || tail != idx) {
|
||||
pr_dbg("invalid idx\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = idx * ring->elem_sz;
|
||||
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
|
||||
|
||||
+47
-23
@@ -24,6 +24,7 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "cpu.h"
|
||||
#include "trace.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#include "../rdma_rm.h"
|
||||
#include "../rdma_backend.h"
|
||||
@@ -36,9 +37,9 @@
|
||||
#include "pvrdma_qp_ops.h"
|
||||
|
||||
static Property pvrdma_dev_properties[] = {
|
||||
DEFINE_PROP_STRING("backend-dev", PVRDMADev, backend_device_name),
|
||||
DEFINE_PROP_UINT8("backend-port", PVRDMADev, backend_port_num, 1),
|
||||
DEFINE_PROP_UINT8("backend-gid-idx", PVRDMADev, backend_gid_idx, 0),
|
||||
DEFINE_PROP_STRING("netdev", PVRDMADev, backend_eth_device_name),
|
||||
DEFINE_PROP_STRING("ibdev", PVRDMADev, backend_device_name),
|
||||
DEFINE_PROP_UINT8("ibport", PVRDMADev, backend_port_num, 1),
|
||||
DEFINE_PROP_UINT64("dev-caps-max-mr-size", PVRDMADev, dev_attr.max_mr_size,
|
||||
MAX_MR_SIZE),
|
||||
DEFINE_PROP_INT32("dev-caps-max-qp", PVRDMADev, dev_attr.max_qp, MAX_QP),
|
||||
@@ -51,6 +52,7 @@ static Property pvrdma_dev_properties[] = {
|
||||
DEFINE_PROP_INT32("dev-caps-max-qp-init-rd-atom", PVRDMADev,
|
||||
dev_attr.max_qp_init_rd_atom, MAX_QP_INIT_RD_ATOM),
|
||||
DEFINE_PROP_INT32("dev-caps-max-ah", PVRDMADev, dev_attr.max_ah, MAX_AH),
|
||||
DEFINE_PROP_CHR("mad-chardev", PVRDMADev, mad_chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -263,7 +265,7 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
|
||||
dsr->caps.sys_image_guid = 0;
|
||||
pr_dbg("sys_image_guid=%" PRIx64 "\n", dsr->caps.sys_image_guid);
|
||||
|
||||
dsr->caps.node_guid = cpu_to_be64(dev->node_guid);
|
||||
dsr->caps.node_guid = dev->node_guid;
|
||||
pr_dbg("node_guid=%" PRIx64 "\n", be64_to_cpu(dsr->caps.node_guid));
|
||||
|
||||
dsr->caps.phys_port_cnt = MAX_PORTS;
|
||||
@@ -275,17 +277,6 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
|
||||
pr_dbg("Initialized\n");
|
||||
}
|
||||
|
||||
static void init_ports(PVRDMADev *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(dev->rdma_dev_res.ports, 0, sizeof(dev->rdma_dev_res.ports));
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
dev->rdma_dev_res.ports[i].state = IBV_PORT_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void uninit_msix(PCIDevice *pdev, int used_vectors)
|
||||
{
|
||||
PVRDMADev *dev = PVRDMA_DEV(pdev);
|
||||
@@ -334,7 +325,8 @@ static void pvrdma_fini(PCIDevice *pdev)
|
||||
|
||||
pvrdma_qp_ops_fini();
|
||||
|
||||
rdma_rm_fini(&dev->rdma_dev_res);
|
||||
rdma_rm_fini(&dev->rdma_dev_res, &dev->backend_dev,
|
||||
dev->backend_eth_device_name);
|
||||
|
||||
rdma_backend_fini(&dev->backend_dev);
|
||||
|
||||
@@ -343,6 +335,9 @@ static void pvrdma_fini(PCIDevice *pdev)
|
||||
if (msix_enabled(pdev)) {
|
||||
uninit_msix(pdev, RDMA_MAX_INTRS);
|
||||
}
|
||||
|
||||
pr_dbg("Device %s %x.%x is down\n", pdev->name, PCI_SLOT(pdev->devfn),
|
||||
PCI_FUNC(pdev->devfn));
|
||||
}
|
||||
|
||||
static void pvrdma_stop(PVRDMADev *dev)
|
||||
@@ -368,13 +363,11 @@ static int unquiesce_device(PVRDMADev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_device(PVRDMADev *dev)
|
||||
static void reset_device(PVRDMADev *dev)
|
||||
{
|
||||
pvrdma_stop(dev);
|
||||
|
||||
pr_dbg("Device reset complete\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t regs_read(void *opaque, hwaddr addr, unsigned size)
|
||||
@@ -455,6 +448,11 @@ static const MemoryRegionOps regs_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t uar_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
{
|
||||
PVRDMADev *dev = opaque;
|
||||
@@ -496,6 +494,7 @@ static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uar_ops = {
|
||||
.read = uar_read,
|
||||
.write = uar_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
@@ -570,12 +569,21 @@ static int pvrdma_check_ram_shared(Object *obj, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pvrdma_shutdown_notifier(Notifier *n, void *opaque)
|
||||
{
|
||||
PVRDMADev *dev = container_of(n, PVRDMADev, shutdown_notifier);
|
||||
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||
|
||||
pvrdma_fini(pci_dev);
|
||||
}
|
||||
|
||||
static void pvrdma_realize(PCIDevice *pdev, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
PVRDMADev *dev = PVRDMA_DEV(pdev);
|
||||
Object *memdev_root;
|
||||
bool ram_shared = false;
|
||||
PCIDevice *func0;
|
||||
|
||||
init_pr_dbg();
|
||||
|
||||
@@ -587,6 +595,20 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
func0 = pci_get_function_0(pdev);
|
||||
/* Break if not vmxnet3 device in slot 0 */
|
||||
if (strcmp(object_get_typename(&func0->qdev.parent_obj), TYPE_VMXNET3)) {
|
||||
pr_dbg("func0 type is %s\n",
|
||||
object_get_typename(&func0->qdev.parent_obj));
|
||||
error_setg(errp, "Device on %x.0 must be %s", PCI_SLOT(pdev->devfn),
|
||||
TYPE_VMXNET3);
|
||||
return;
|
||||
}
|
||||
dev->func0 = VMXNET3(func0);
|
||||
|
||||
addrconf_addr_eui48((unsigned char *)&dev->node_guid,
|
||||
(const char *)&dev->func0->conf.macaddr.a);
|
||||
|
||||
memdev_root = object_resolve_path("/objects", NULL);
|
||||
if (memdev_root) {
|
||||
object_child_foreach(memdev_root, pvrdma_check_ram_shared, &ram_shared);
|
||||
@@ -613,7 +635,7 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
|
||||
|
||||
rc = rdma_backend_init(&dev->backend_dev, pdev, &dev->rdma_dev_res,
|
||||
dev->backend_device_name, dev->backend_port_num,
|
||||
dev->backend_gid_idx, &dev->dev_attr, errp);
|
||||
&dev->dev_attr, &dev->mad_chr, errp);
|
||||
if (rc) {
|
||||
goto out;
|
||||
}
|
||||
@@ -623,15 +645,17 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
init_ports(dev, errp);
|
||||
|
||||
rc = pvrdma_qp_ops_init();
|
||||
if (rc) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->shutdown_notifier.notify = pvrdma_shutdown_notifier;
|
||||
qemu_register_shutdown_notifier(&dev->shutdown_notifier);
|
||||
|
||||
out:
|
||||
if (rc) {
|
||||
pvrdma_fini(pdev);
|
||||
error_append_hint(errp, "Device fail to load\n");
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user