a2a23a794b
When a VF device is present, netvsc can send or receive packets over the VF device. The VF device driver communicates directly with the PCI device via the PF from the host hypervisor. This is faster than exchanging data with netvsp via vmbus, i.e. syntheic path. In Azure and Hyper-v environments, VF device can be hot added or hot removed at anytime while guest VM is running. This patch improves netvsc to support VF device hot add/remove. 1. netvsc monitors all system hot add activities over the PCI bus. When it detects a VF device is added to the system and is managed under this netvsc device, it asks EAL to probe and start this VF device, then it attaches and switches data path to the VF device. 2. After a VF device is attached to netvsc, netvsc monitors this device on hot remove. When this VF device is hot removed, netvsc switches data path to synthetic, stops this VF device and removes it from EAL. 3. If any failure happens during a VF device hot remove or add, the netvsc falls back to synthetic path for all data traffic. Signed-off-by: Long Li <longli@microsoft.com>
239 lines
5.8 KiB
C
239 lines
5.8 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (c) 2018 Microsoft Corp.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/*
|
|
* The indirection table message is the largest message
|
|
* received from host, and that is 112 bytes.
|
|
*/
|
|
#define NVS_RESPSIZE_MAX 256
|
|
|
|
/*
|
|
* NDIS protocol version numbers
|
|
*/
|
|
#define NDIS_VERSION_6_1 0x00060001
|
|
#define NDIS_VERSION_6_20 0x00060014
|
|
#define NDIS_VERSION_6_30 0x0006001e
|
|
#define NDIS_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16)
|
|
#define NDIS_VERSION_MINOR(ver) ((ver) & 0xffff)
|
|
|
|
/*
|
|
* NVS versions.
|
|
*/
|
|
#define NVS_VERSION_1 0x00002
|
|
#define NVS_VERSION_2 0x30002
|
|
#define NVS_VERSION_4 0x40000
|
|
#define NVS_VERSION_5 0x50000
|
|
#define NVS_VERSION_6 0x60000
|
|
#define NVS_VERSION_61 0x60001
|
|
|
|
#define NVS_RXBUF_SIG 0xcafe
|
|
#define NVS_CHIM_SIG 0xface
|
|
|
|
#define NVS_CHIM_IDX_INVALID 0xffffffff
|
|
|
|
#define NVS_RNDIS_MTYPE_DATA 0
|
|
#define NVS_RNDIS_MTYPE_CTRL 1
|
|
|
|
/*
|
|
* NVS message transaction status codes.
|
|
*/
|
|
#define NVS_STATUS_OK 1
|
|
#define NVS_STATUS_FAILED 2
|
|
|
|
/*
|
|
* NVS request/response message types.
|
|
*/
|
|
#define NVS_TYPE_INIT 1
|
|
#define NVS_TYPE_INIT_RESP 2
|
|
|
|
#define NVS_TYPE_NDIS_INIT 100
|
|
#define NVS_TYPE_RXBUF_CONN 101
|
|
#define NVS_TYPE_RXBUF_CONNRESP 102
|
|
#define NVS_TYPE_RXBUF_DISCONN 103
|
|
#define NVS_TYPE_CHIM_CONN 104
|
|
#define NVS_TYPE_CHIM_CONNRESP 105
|
|
#define NVS_TYPE_CHIM_DISCONN 106
|
|
#define NVS_TYPE_RNDIS 107
|
|
#define NVS_TYPE_RNDIS_ACK 108
|
|
|
|
#define NVS_TYPE_NDIS_CONF 125
|
|
#define NVS_TYPE_VFASSOC_NOTE 128 /* notification */
|
|
#define NVS_TYPE_SET_DATAPATH 129
|
|
#define NVS_TYPE_SUBCH_REQ 133
|
|
#define NVS_TYPE_SUBCH_RESP 133 /* same as SUBCH_REQ */
|
|
#define NVS_TYPE_TXTBL_NOTE 134 /* notification */
|
|
|
|
|
|
/* NVS message common header */
|
|
struct hn_nvs_hdr {
|
|
uint32_t type;
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_init {
|
|
uint32_t type; /* NVS_TYPE_INIT */
|
|
uint32_t ver_min;
|
|
uint32_t ver_max;
|
|
uint8_t rsvd[28];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_init_resp {
|
|
uint32_t type; /* NVS_TYPE_INIT_RESP */
|
|
uint32_t ver; /* deprecated */
|
|
uint32_t rsvd;
|
|
uint32_t status; /* NVS_STATUS_ */
|
|
} __rte_packed;
|
|
|
|
/* No response */
|
|
struct hn_nvs_ndis_conf {
|
|
uint32_t type; /* NVS_TYPE_NDIS_CONF */
|
|
uint32_t mtu;
|
|
uint32_t rsvd;
|
|
uint64_t caps; /* NVS_NDIS_CONF_ */
|
|
uint8_t rsvd1[20];
|
|
} __rte_packed;
|
|
|
|
#define NVS_NDIS_CONF_SRIOV 0x0004
|
|
#define NVS_NDIS_CONF_VLAN 0x0008
|
|
|
|
/* No response */
|
|
struct hn_nvs_ndis_init {
|
|
uint32_t type; /* NVS_TYPE_NDIS_INIT */
|
|
uint32_t ndis_major; /* NDIS_VERSION_MAJOR_ */
|
|
uint32_t ndis_minor; /* NDIS_VERSION_MINOR_ */
|
|
uint8_t rsvd[28];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_vf_association {
|
|
uint32_t type; /* NVS_TYPE_VFASSOC_NOTE */
|
|
uint32_t allocated;
|
|
uint32_t serial;
|
|
} __rte_packed;
|
|
|
|
#define NVS_DATAPATH_SYNTHETIC 0
|
|
#define NVS_DATAPATH_VF 1
|
|
|
|
/* No response */
|
|
struct hn_nvs_datapath {
|
|
uint32_t type; /* NVS_TYPE_SET_DATAPATH */
|
|
uint32_t active_path;/* NVS_DATAPATH_* */
|
|
uint8_t rsvd[32];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_rxbuf_conn {
|
|
uint32_t type; /* NVS_TYPE_RXBUF_CONN */
|
|
uint32_t gpadl; /* RXBUF vmbus GPADL */
|
|
uint16_t sig; /* NVS_RXBUF_SIG */
|
|
uint8_t rsvd[30];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_rxbuf_sect {
|
|
uint32_t start;
|
|
uint32_t slotsz;
|
|
uint32_t slotcnt;
|
|
uint32_t end;
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_rxbuf_connresp {
|
|
uint32_t type; /* NVS_TYPE_RXBUF_CONNRESP */
|
|
uint32_t status; /* NVS_STATUS_ */
|
|
uint32_t nsect; /* # of elem in nvs_sect */
|
|
struct hn_nvs_rxbuf_sect nvs_sect[1];
|
|
} __rte_packed;
|
|
|
|
/* No response */
|
|
struct hn_nvs_rxbuf_disconn {
|
|
uint32_t type; /* NVS_TYPE_RXBUF_DISCONN */
|
|
uint16_t sig; /* NVS_RXBUF_SIG */
|
|
uint8_t rsvd[34];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_chim_conn {
|
|
uint32_t type; /* NVS_TYPE_CHIM_CONN */
|
|
uint32_t gpadl; /* chimney buf vmbus GPADL */
|
|
uint16_t sig; /* NDIS_NVS_CHIM_SIG */
|
|
uint8_t rsvd[30];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_chim_connresp {
|
|
uint32_t type; /* NVS_TYPE_CHIM_CONNRESP */
|
|
uint32_t status; /* NVS_STATUS_ */
|
|
uint32_t sectsz; /* section size */
|
|
} __rte_packed;
|
|
|
|
/* No response */
|
|
struct hn_nvs_chim_disconn {
|
|
uint32_t type; /* NVS_TYPE_CHIM_DISCONN */
|
|
uint16_t sig; /* NVS_CHIM_SIG */
|
|
uint8_t rsvd[34];
|
|
} __rte_packed;
|
|
|
|
#define NVS_SUBCH_OP_ALLOC 1
|
|
|
|
struct hn_nvs_subch_req {
|
|
uint32_t type; /* NVS_TYPE_SUBCH_REQ */
|
|
uint32_t op; /* NVS_SUBCH_OP_ */
|
|
uint32_t nsubch;
|
|
uint8_t rsvd[28];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_subch_resp {
|
|
uint32_t type; /* NVS_TYPE_SUBCH_RESP */
|
|
uint32_t status; /* NVS_STATUS_ */
|
|
uint32_t nsubch;
|
|
uint8_t rsvd[28];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_rndis {
|
|
uint32_t type; /* NVS_TYPE_RNDIS */
|
|
uint32_t rndis_mtype;/* NVS_RNDIS_MTYPE_ */
|
|
/*
|
|
* Chimney sending buffer index and size.
|
|
*
|
|
* NOTE:
|
|
* If nvs_chim_idx is set to NVS_CHIM_IDX_INVALID
|
|
* and nvs_chim_sz is set to 0, then chimney sending
|
|
* buffer is _not_ used by this RNDIS message.
|
|
*/
|
|
uint32_t chim_idx;
|
|
uint32_t chim_sz;
|
|
uint8_t rsvd[24];
|
|
} __rte_packed;
|
|
|
|
struct hn_nvs_rndis_ack {
|
|
uint32_t type; /* NVS_TYPE_RNDIS_ACK */
|
|
uint32_t status; /* NVS_STATUS_ */
|
|
uint8_t rsvd[32];
|
|
} __rte_packed;
|
|
|
|
|
|
int hn_nvs_attach(struct hn_data *hv, unsigned int mtu);
|
|
void hn_nvs_detach(struct hn_data *hv);
|
|
void hn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid);
|
|
int hn_nvs_alloc_subchans(struct hn_data *hv, uint32_t *nsubch);
|
|
int hn_nvs_set_datapath(struct hn_data *hv, uint32_t path);
|
|
void hn_nvs_handle_vfassoc(struct rte_eth_dev *dev,
|
|
const struct vmbus_chanpkt_hdr *hdr,
|
|
const void *data);
|
|
|
|
static inline int
|
|
hn_nvs_send(struct vmbus_channel *chan, uint16_t flags,
|
|
void *nvs_msg, int nvs_msglen, uintptr_t sndc,
|
|
bool *need_sig)
|
|
{
|
|
return rte_vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND,
|
|
nvs_msg, nvs_msglen, (uint64_t)sndc,
|
|
flags, need_sig);
|
|
}
|
|
|
|
static inline int
|
|
hn_nvs_send_sglist(struct vmbus_channel *chan,
|
|
struct vmbus_gpa sg[], unsigned int sglen,
|
|
void *nvs_msg, int nvs_msglen,
|
|
uintptr_t sndc, bool *need_sig)
|
|
{
|
|
return rte_vmbus_chan_send_sglist(chan, sg, sglen, nvs_msg, nvs_msglen,
|
|
(uint64_t)sndc, need_sig);
|
|
}
|