hyperv/vmbus: Cleanup channel packet receiving.
MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D7204
This commit is contained in:
parent
7c55724859
commit
43bbe6b27f
@ -90,28 +90,6 @@ struct hyperv_guid {
|
||||
|
||||
int hyperv_guid2str(const struct hyperv_guid *, char *, size_t);
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t data_offset8;
|
||||
uint16_t length8;
|
||||
uint16_t flags;
|
||||
uint64_t transaction_id;
|
||||
} __packed hv_vm_packet_descriptor;
|
||||
|
||||
typedef struct {
|
||||
uint32_t byte_count;
|
||||
uint32_t byte_offset;
|
||||
} __packed hv_vm_transfer_page;
|
||||
|
||||
typedef struct {
|
||||
hv_vm_packet_descriptor d;
|
||||
uint16_t transfer_page_set_id;
|
||||
hv_bool_uint8_t sender_owns_set;
|
||||
uint8_t reserved;
|
||||
uint32_t range_count;
|
||||
hv_vm_transfer_page ranges[1];
|
||||
} __packed hv_vm_transfer_page_packet_header;
|
||||
|
||||
#define HW_MACADDR_LEN 6
|
||||
|
||||
/*
|
||||
@ -298,13 +276,6 @@ hv_set_channel_read_state(hv_vmbus_channel* channel, boolean_t on)
|
||||
channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
|
||||
}
|
||||
|
||||
int hv_vmbus_channel_recv_packet_raw(
|
||||
hv_vmbus_channel* channel,
|
||||
void* buffer,
|
||||
uint32_t buffer_len,
|
||||
uint32_t* buffer_actual_len,
|
||||
uint64_t* request_id);
|
||||
|
||||
int hv_vmbus_channel_open(
|
||||
hv_vmbus_channel* channel,
|
||||
uint32_t send_ring_buffer_size,
|
||||
|
@ -47,6 +47,19 @@ struct vmbus_gpa {
|
||||
uint64_t gpa_page;
|
||||
} __packed;
|
||||
|
||||
#define VMBUS_CHANPKT_SIZE_SHIFT 3
|
||||
|
||||
#define VMBUS_CHANPKT_GETLEN(pktlen) \
|
||||
(((int)(pktlen)) << VMBUS_CHANPKT_SIZE_SHIFT)
|
||||
|
||||
struct vmbus_chanpkt_hdr {
|
||||
uint16_t cph_type; /* VMBUS_CHANPKT_TYPE_ */
|
||||
uint16_t cph_hlen; /* header len, in 8 bytes */
|
||||
uint16_t cph_tlen; /* total len, in 8 bytes */
|
||||
uint16_t cph_flags; /* VMBUS_CHANPKT_FLAG_ */
|
||||
uint64_t cph_xactid;
|
||||
} __packed;
|
||||
|
||||
#define VMBUS_CHANPKT_TYPE_INBAND 0x0006
|
||||
#define VMBUS_CHANPKT_TYPE_RXBUF 0x0007
|
||||
#define VMBUS_CHANPKT_TYPE_GPA 0x0009
|
||||
@ -54,6 +67,23 @@ struct vmbus_gpa {
|
||||
|
||||
#define VMBUS_CHANPKT_FLAG_RC 0x0001 /* report completion */
|
||||
|
||||
#define VMBUS_CHANPKT_CONST_DATA(pkt) \
|
||||
(const void *)((const uint8_t *)(pkt) + \
|
||||
VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
|
||||
|
||||
struct vmbus_rxbuf_desc {
|
||||
uint32_t rb_len;
|
||||
uint32_t rb_ofs;
|
||||
} __packed;
|
||||
|
||||
struct vmbus_chanpkt_rxbuf {
|
||||
struct vmbus_chanpkt_hdr cp_hdr;
|
||||
uint16_t cp_rxbuf_id;
|
||||
uint16_t cp_rsvd;
|
||||
uint32_t cp_rxbuf_cnt;
|
||||
struct vmbus_rxbuf_desc cp_rxbuf[];
|
||||
} __packed;
|
||||
|
||||
#define VMBUS_CHAN_SGLIST_MAX 32
|
||||
#define VMBUS_CHAN_PRPLIST_MAX 32
|
||||
|
||||
@ -61,6 +91,8 @@ struct hv_vmbus_channel;
|
||||
|
||||
int vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen,
|
||||
uint64_t *xactid);
|
||||
int vmbus_chan_recv_pkt(struct hv_vmbus_channel *chan,
|
||||
struct vmbus_chanpkt_hdr *pkt, int *pktlen);
|
||||
|
||||
int vmbus_chan_send(struct hv_vmbus_channel *chan, uint16_t type,
|
||||
uint16_t flags, void *data, int dlen, uint64_t xactid);
|
||||
|
@ -64,12 +64,12 @@ static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
|
||||
static int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
|
||||
static int hv_nv_connect_to_vsp(struct hn_softc *sc);
|
||||
static void hv_nv_on_send_completion(netvsc_dev *net_dev,
|
||||
struct hv_vmbus_channel *, hv_vm_packet_descriptor *pkt);
|
||||
struct hv_vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt);
|
||||
static void hv_nv_on_receive_completion(struct hv_vmbus_channel *chan,
|
||||
uint64_t tid, uint32_t status);
|
||||
static void hv_nv_on_receive(netvsc_dev *net_dev,
|
||||
struct hn_softc *sc, struct hv_vmbus_channel *chan,
|
||||
hv_vm_packet_descriptor *pkt);
|
||||
const struct vmbus_chanpkt_hdr *pkt);
|
||||
|
||||
/*
|
||||
*
|
||||
@ -726,13 +726,12 @@ hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
|
||||
*/
|
||||
static void
|
||||
hv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan,
|
||||
hv_vm_packet_descriptor *pkt)
|
||||
const struct vmbus_chanpkt_hdr *pkt)
|
||||
{
|
||||
nvsp_msg *nvsp_msg_pkt;
|
||||
const nvsp_msg *nvsp_msg_pkt;
|
||||
netvsc_packet *net_vsc_pkt;
|
||||
|
||||
nvsp_msg_pkt =
|
||||
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
|
||||
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
|
||||
|
||||
if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
|
||||
|| nvsp_msg_pkt->hdr.msg_type
|
||||
@ -749,7 +748,7 @@ hv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan,
|
||||
nvsp_msg_1_type_send_rndis_pkt_complete) {
|
||||
/* Get the send context */
|
||||
net_vsc_pkt =
|
||||
(netvsc_packet *)(unsigned long)pkt->transaction_id;
|
||||
(netvsc_packet *)(unsigned long)pkt->cph_xactid;
|
||||
if (NULL != net_vsc_pkt) {
|
||||
if (net_vsc_pkt->send_buf_section_idx !=
|
||||
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
|
||||
@ -829,10 +828,10 @@ hv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt)
|
||||
*/
|
||||
static void
|
||||
hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
|
||||
struct hv_vmbus_channel *chan, hv_vm_packet_descriptor *pkt)
|
||||
struct hv_vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
|
||||
{
|
||||
hv_vm_transfer_page_packet_header *vm_xfer_page_pkt;
|
||||
nvsp_msg *nvsp_msg_pkt;
|
||||
const struct vmbus_chanpkt_rxbuf *pkt;
|
||||
const nvsp_msg *nvsp_msg_pkt;
|
||||
netvsc_packet vsc_pkt;
|
||||
netvsc_packet *net_vsc_pkt = &vsc_pkt;
|
||||
device_t dev = sc->hn_dev;
|
||||
@ -840,43 +839,31 @@ hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
|
||||
int i = 0;
|
||||
int status = nvsp_status_success;
|
||||
|
||||
/*
|
||||
* All inbound packets other than send completion should be
|
||||
* xfer page packet.
|
||||
*/
|
||||
if (pkt->type != VMBUS_CHANPKT_TYPE_RXBUF) {
|
||||
device_printf(dev, "packet type %d is invalid!\n", pkt->type);
|
||||
return;
|
||||
}
|
||||
|
||||
nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt
|
||||
+ (pkt->data_offset8 << 3));
|
||||
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkthdr);
|
||||
|
||||
/* Make sure this is a valid nvsp packet */
|
||||
if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) {
|
||||
device_printf(dev, "packet hdr type %d is invalid!\n",
|
||||
pkt->type);
|
||||
device_printf(dev, "packet hdr type %u is invalid!\n",
|
||||
nvsp_msg_pkt->hdr.msg_type);
|
||||
return;
|
||||
}
|
||||
|
||||
vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt;
|
||||
pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
|
||||
|
||||
if (vm_xfer_page_pkt->transfer_page_set_id !=
|
||||
NETVSC_RECEIVE_BUFFER_ID) {
|
||||
device_printf(dev, "transfer_page_set_id %d is invalid!\n",
|
||||
vm_xfer_page_pkt->transfer_page_set_id);
|
||||
if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) {
|
||||
device_printf(dev, "rxbuf_id %d is invalid!\n",
|
||||
pkt->cp_rxbuf_id);
|
||||
return;
|
||||
}
|
||||
|
||||
count = vm_xfer_page_pkt->range_count;
|
||||
count = pkt->cp_rxbuf_cnt;
|
||||
|
||||
/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
|
||||
for (i = 0; i < count; i++) {
|
||||
net_vsc_pkt->status = nvsp_status_success;
|
||||
net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf +
|
||||
vm_xfer_page_pkt->ranges[i].byte_offset);
|
||||
net_vsc_pkt->tot_data_buf_len =
|
||||
vm_xfer_page_pkt->ranges[i].byte_count;
|
||||
net_vsc_pkt->data = ((uint8_t *)net_dev->rx_buf +
|
||||
pkt->cp_rxbuf[i].rb_ofs);
|
||||
net_vsc_pkt->tot_data_buf_len = pkt->cp_rxbuf[i].rb_len;
|
||||
|
||||
hv_rf_on_receive(net_dev, chan, net_vsc_pkt);
|
||||
if (net_vsc_pkt->status != nvsp_status_success) {
|
||||
@ -889,8 +876,7 @@ hv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
|
||||
* messages (not just data messages) will trigger a response
|
||||
* message back to the host.
|
||||
*/
|
||||
hv_nv_on_receive_completion(chan, vm_xfer_page_pkt->d.transaction_id,
|
||||
status);
|
||||
hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid, status);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -934,19 +920,19 @@ hv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid,
|
||||
* Net VSC receiving vRSS send table from VSP
|
||||
*/
|
||||
static void
|
||||
hv_nv_send_table(struct hn_softc *sc, hv_vm_packet_descriptor *pkt)
|
||||
hv_nv_send_table(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
|
||||
{
|
||||
netvsc_dev *net_dev;
|
||||
nvsp_msg *nvsp_msg_pkt;
|
||||
const nvsp_msg *nvsp_msg_pkt;
|
||||
int i;
|
||||
uint32_t count, *table;
|
||||
uint32_t count;
|
||||
const uint32_t *table;
|
||||
|
||||
net_dev = hv_nv_get_inbound_net_device(sc);
|
||||
if (!net_dev)
|
||||
return;
|
||||
|
||||
nvsp_msg_pkt =
|
||||
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
|
||||
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
|
||||
|
||||
if (nvsp_msg_pkt->hdr.msg_type !=
|
||||
nvsp_msg5_type_send_indirection_table) {
|
||||
@ -962,8 +948,8 @@ hv_nv_send_table(struct hn_softc *sc, hv_vm_packet_descriptor *pkt)
|
||||
return;
|
||||
}
|
||||
|
||||
table = (uint32_t *)
|
||||
((unsigned long)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
|
||||
table = (const uint32_t *)
|
||||
((const uint8_t *)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
|
||||
nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
@ -980,44 +966,40 @@ hv_nv_on_channel_callback(void *xchan)
|
||||
device_t dev = chan->ch_dev;
|
||||
struct hn_softc *sc = device_get_softc(dev);
|
||||
netvsc_dev *net_dev;
|
||||
uint32_t bytes_rxed;
|
||||
uint64_t request_id;
|
||||
hv_vm_packet_descriptor *desc;
|
||||
uint8_t *buffer;
|
||||
void *buffer;
|
||||
int bufferlen = NETVSC_PACKET_SIZE;
|
||||
int ret = 0;
|
||||
|
||||
net_dev = hv_nv_get_inbound_net_device(sc);
|
||||
if (net_dev == NULL)
|
||||
return;
|
||||
|
||||
buffer = chan->hv_chan_rdbuf;
|
||||
|
||||
do {
|
||||
ret = hv_vmbus_channel_recv_packet_raw(chan,
|
||||
buffer, bufferlen, &bytes_rxed, &request_id);
|
||||
struct vmbus_chanpkt_hdr *pkt = buffer;
|
||||
uint32_t bytes_rxed;
|
||||
int ret;
|
||||
|
||||
bytes_rxed = bufferlen;
|
||||
ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed);
|
||||
if (ret == 0) {
|
||||
if (bytes_rxed > 0) {
|
||||
desc = (hv_vm_packet_descriptor *)buffer;
|
||||
switch (desc->type) {
|
||||
switch (pkt->cph_type) {
|
||||
case VMBUS_CHANPKT_TYPE_COMP:
|
||||
hv_nv_on_send_completion(net_dev, chan,
|
||||
desc);
|
||||
pkt);
|
||||
break;
|
||||
case VMBUS_CHANPKT_TYPE_RXBUF:
|
||||
hv_nv_on_receive(net_dev, sc, chan, desc);
|
||||
hv_nv_on_receive(net_dev, sc, chan, pkt);
|
||||
break;
|
||||
case VMBUS_CHANPKT_TYPE_INBAND:
|
||||
hv_nv_send_table(sc, desc);
|
||||
hv_nv_send_table(sc, pkt);
|
||||
break;
|
||||
default:
|
||||
device_printf(dev,
|
||||
"hv_cb recv unknow type %d "
|
||||
" packet\n", desc->type);
|
||||
"unknown chan pkt %u\n",
|
||||
pkt->cph_type);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (ret == ENOBUFS) {
|
||||
/* Handle large packet */
|
||||
@ -1036,6 +1018,9 @@ hv_nv_on_channel_callback(void *xchan)
|
||||
break;
|
||||
}
|
||||
bufferlen = bytes_rxed;
|
||||
} else {
|
||||
/* No more packets */
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
|
@ -751,7 +751,7 @@ vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen0,
|
||||
dlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen) - hlen;
|
||||
|
||||
if (*dlen0 < dlen) {
|
||||
/* Return the size of this packet. */
|
||||
/* Return the size of this packet's data. */
|
||||
*dlen0 = dlen;
|
||||
return ENOBUFS;
|
||||
}
|
||||
@ -759,49 +759,37 @@ vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen0,
|
||||
*xactid = pkt.cph_xactid;
|
||||
*dlen0 = dlen;
|
||||
|
||||
/* Skip packet header */
|
||||
error = hv_ring_buffer_read(&chan->inbound, data, dlen, hlen);
|
||||
KASSERT(!error, ("hv_ring_buffer_read failed"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the raw packet on the specified channel
|
||||
*/
|
||||
int
|
||||
hv_vmbus_channel_recv_packet_raw(
|
||||
hv_vmbus_channel* channel,
|
||||
void* buffer,
|
||||
uint32_t buffer_len,
|
||||
uint32_t* buffer_actual_len,
|
||||
uint64_t* request_id)
|
||||
vmbus_chan_recv_pkt(struct hv_vmbus_channel *chan,
|
||||
struct vmbus_chanpkt_hdr *pkt0, int *pktlen0)
|
||||
{
|
||||
int ret;
|
||||
uint32_t packetLen;
|
||||
hv_vm_packet_descriptor desc;
|
||||
struct vmbus_chanpkt_hdr pkt;
|
||||
int error, pktlen;
|
||||
|
||||
*buffer_actual_len = 0;
|
||||
*request_id = 0;
|
||||
error = hv_ring_buffer_peek(&chan->inbound, &pkt, sizeof(pkt));
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ret = hv_ring_buffer_peek(
|
||||
&channel->inbound, &desc,
|
||||
sizeof(hv_vm_packet_descriptor));
|
||||
pktlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen);
|
||||
if (*pktlen0 < pktlen) {
|
||||
/* Return the size of this packet. */
|
||||
*pktlen0 = pktlen;
|
||||
return ENOBUFS;
|
||||
}
|
||||
*pktlen0 = pktlen;
|
||||
|
||||
if (ret != 0)
|
||||
return (0);
|
||||
/* Include packet header */
|
||||
error = hv_ring_buffer_read(&chan->inbound, pkt0, pktlen, 0);
|
||||
KASSERT(!error, ("hv_ring_buffer_read failed"));
|
||||
|
||||
packetLen = desc.length8 << 3;
|
||||
*buffer_actual_len = packetLen;
|
||||
|
||||
if (packetLen > buffer_len)
|
||||
return (ENOBUFS);
|
||||
|
||||
*request_id = desc.transaction_id;
|
||||
|
||||
/* Copy over the entire packet to the user buffer */
|
||||
ret = hv_ring_buffer_read(&channel->inbound, buffer, packetLen, 0);
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -112,7 +112,6 @@ CTASSERT(sizeof(struct vmbus_mnf) == PAGE_SIZE);
|
||||
* Channel packets
|
||||
*/
|
||||
|
||||
#define VMBUS_CHANPKT_SIZE_SHIFT 3
|
||||
#define VMBUS_CHANPKT_SIZE_ALIGN (1 << VMBUS_CHANPKT_SIZE_SHIFT)
|
||||
|
||||
#define VMBUS_CHANPKT_SETLEN(pktlen, len) \
|
||||
@ -120,20 +119,9 @@ do { \
|
||||
(pktlen) = (len) >> VMBUS_CHANPKT_SIZE_SHIFT; \
|
||||
} while (0)
|
||||
|
||||
#define VMBUS_CHANPKT_GETLEN(pktlen) \
|
||||
(((int)(pktlen)) << VMBUS_CHANPKT_SIZE_SHIFT)
|
||||
|
||||
#define VMBUS_CHANPKT_TOTLEN(tlen) \
|
||||
roundup2((tlen), VMBUS_CHANPKT_SIZE_ALIGN)
|
||||
|
||||
struct vmbus_chanpkt_hdr {
|
||||
uint16_t cph_type;
|
||||
uint16_t cph_hlen; /* header len, in 8 bytes */
|
||||
uint16_t cph_tlen; /* total len, in 8 bytes */
|
||||
uint16_t cph_flags;
|
||||
uint64_t cph_xactid;
|
||||
} __packed;
|
||||
|
||||
struct vmbus_chanpkt {
|
||||
struct vmbus_chanpkt_hdr cp_hdr;
|
||||
} __packed;
|
||||
|
Loading…
Reference in New Issue
Block a user