hyperv/hn: Reorganize send done callback.
MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7450
This commit is contained in:
parent
08dde4d421
commit
127d6d1a64
@ -68,6 +68,12 @@ static void hv_nv_on_receive_completion(struct vmbus_channel *chan,
|
|||||||
static void hv_nv_on_receive(netvsc_dev *net_dev,
|
static void hv_nv_on_receive(netvsc_dev *net_dev,
|
||||||
struct hn_rx_ring *rxr, struct vmbus_channel *chan,
|
struct hn_rx_ring *rxr, struct vmbus_channel *chan,
|
||||||
const struct vmbus_chanpkt_hdr *pkt);
|
const struct vmbus_chanpkt_hdr *pkt);
|
||||||
|
static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
|
||||||
|
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
|
||||||
|
const struct nvsp_msg_ *msg);
|
||||||
|
|
||||||
|
static struct hn_send_ctx hn_send_ctx_none =
|
||||||
|
HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -141,6 +147,7 @@ hv_nv_get_next_send_section(netvsc_dev *net_dev)
|
|||||||
static int
|
static int
|
||||||
hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
|
hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
|
||||||
{
|
{
|
||||||
|
struct hn_send_ctx sndc;
|
||||||
netvsc_dev *net_dev;
|
netvsc_dev *net_dev;
|
||||||
nvsp_msg *init_pkt;
|
nvsp_msg *init_pkt;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -189,9 +196,10 @@ hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
|
|||||||
|
|
||||||
/* Send the gpadl notification request */
|
/* Send the gpadl notification request */
|
||||||
|
|
||||||
|
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
|
||||||
ret = vmbus_chan_send(sc->hn_prichan,
|
ret = vmbus_chan_send(sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -240,6 +248,7 @@ exit:
|
|||||||
static int
|
static int
|
||||||
hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
|
hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
|
||||||
{
|
{
|
||||||
|
struct hn_send_ctx sndc;
|
||||||
netvsc_dev *net_dev;
|
netvsc_dev *net_dev;
|
||||||
nvsp_msg *init_pkt;
|
nvsp_msg *init_pkt;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -287,9 +296,10 @@ hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
|
|||||||
|
|
||||||
/* Send the gpadl notification request */
|
/* Send the gpadl notification request */
|
||||||
|
|
||||||
|
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
|
||||||
ret = vmbus_chan_send(sc->hn_prichan,
|
ret = vmbus_chan_send(sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -348,8 +358,7 @@ hv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
|
|||||||
|
|
||||||
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
|
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
|
VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
|
||||||
(uint64_t)(uintptr_t)revoke_pkt);
|
(uint64_t)(uintptr_t)&hn_send_ctx_none);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we failed here, we might as well return and have a leak
|
* If we failed here, we might as well return and have a leak
|
||||||
* rather than continue and a bugchk
|
* rather than continue and a bugchk
|
||||||
@ -414,9 +423,8 @@ hv_nv_destroy_send_buffer(netvsc_dev *net_dev)
|
|||||||
NETVSC_SEND_BUFFER_ID;
|
NETVSC_SEND_BUFFER_ID;
|
||||||
|
|
||||||
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
|
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, 0,
|
VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
|
||||||
revoke_pkt, sizeof(nvsp_msg),
|
(uint64_t)(uintptr_t)&hn_send_ctx_none);
|
||||||
(uint64_t)(uintptr_t)revoke_pkt);
|
|
||||||
/*
|
/*
|
||||||
* If we failed here, we might as well return and have a leak
|
* If we failed here, we might as well return and have a leak
|
||||||
* rather than continue and a bugchk
|
* rather than continue and a bugchk
|
||||||
@ -466,6 +474,7 @@ static int
|
|||||||
hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
|
hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
|
||||||
uint32_t nvsp_ver)
|
uint32_t nvsp_ver)
|
||||||
{
|
{
|
||||||
|
struct hn_send_ctx sndc;
|
||||||
nvsp_msg *init_pkt;
|
nvsp_msg *init_pkt;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -480,9 +489,10 @@ hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
|
|||||||
init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
|
init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
|
||||||
|
|
||||||
/* Send the init request */
|
/* Send the init request */
|
||||||
|
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
|
||||||
ret = vmbus_chan_send(sc->hn_prichan,
|
ret = vmbus_chan_send(sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
@ -524,7 +534,7 @@ hv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu)
|
|||||||
|
|
||||||
/* Send the configuration packet */
|
/* Send the configuration packet */
|
||||||
ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&hn_send_ctx_none);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (-EINVAL);
|
return (-EINVAL);
|
||||||
|
|
||||||
@ -602,7 +612,7 @@ hv_nv_connect_to_vsp(struct hn_softc *sc)
|
|||||||
/* Send the init request */
|
/* Send the init request */
|
||||||
|
|
||||||
ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&hn_send_ctx_none);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -731,6 +741,43 @@ hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hn_nvs_sent_wakeup(struct hn_send_ctx *sndc __unused,
|
||||||
|
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan __unused,
|
||||||
|
const struct nvsp_msg_ *msg)
|
||||||
|
{
|
||||||
|
/* Copy the response back */
|
||||||
|
memcpy(&net_dev->channel_init_packet, msg, sizeof(nvsp_msg));
|
||||||
|
sema_post(&net_dev->channel_init_sema);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hn_nvs_sent_none(struct hn_send_ctx *sndc __unused,
|
||||||
|
struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused,
|
||||||
|
const struct nvsp_msg_ *msg __unused)
|
||||||
|
{
|
||||||
|
/* EMPTY */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx)
|
||||||
|
{
|
||||||
|
u_long mask;
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
idx = chim_idx / BITS_PER_LONG;
|
||||||
|
KASSERT(idx < net_dev->bitsmap_words,
|
||||||
|
("invalid chimney index 0x%x", chim_idx));
|
||||||
|
|
||||||
|
mask = 1UL << (chim_idx % BITS_PER_LONG);
|
||||||
|
KASSERT(net_dev->send_section_bitsmap[idx] & mask,
|
||||||
|
("index bitmap 0x%lx, chimney index %u, "
|
||||||
|
"bitmap idx %d, bitmask 0x%lx",
|
||||||
|
net_dev->send_section_bitsmap[idx], chim_idx, idx, mask));
|
||||||
|
|
||||||
|
atomic_clear_long(&net_dev->send_section_bitsmap[idx], mask);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Net VSC on send completion
|
* Net VSC on send completion
|
||||||
*/
|
*/
|
||||||
@ -738,59 +785,15 @@ static void
|
|||||||
hv_nv_on_send_completion(netvsc_dev *net_dev, struct vmbus_channel *chan,
|
hv_nv_on_send_completion(netvsc_dev *net_dev, struct vmbus_channel *chan,
|
||||||
const struct vmbus_chanpkt_hdr *pkt)
|
const struct vmbus_chanpkt_hdr *pkt)
|
||||||
{
|
{
|
||||||
const nvsp_msg *nvsp_msg_pkt;
|
struct hn_send_ctx *sndc;
|
||||||
netvsc_packet *net_vsc_pkt;
|
|
||||||
|
|
||||||
nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
|
sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid;
|
||||||
|
sndc->hn_cb(sndc, net_dev, chan, VMBUS_CHANPKT_CONST_DATA(pkt));
|
||||||
if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
|
/*
|
||||||
|| nvsp_msg_pkt->hdr.msg_type
|
* NOTE:
|
||||||
== nvsp_msg_1_type_send_rx_buf_complete
|
* 'sndc' CAN NOT be accessed anymore, since it can be freed by
|
||||||
|| nvsp_msg_pkt->hdr.msg_type
|
* its callback.
|
||||||
== nvsp_msg_1_type_send_send_buf_complete
|
*/
|
||||||
|| nvsp_msg_pkt->hdr.msg_type
|
|
||||||
== nvsp_msg5_type_subchannel) {
|
|
||||||
/* Copy the response back */
|
|
||||||
memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt,
|
|
||||||
sizeof(nvsp_msg));
|
|
||||||
sema_post(&net_dev->channel_init_sema);
|
|
||||||
} else if (nvsp_msg_pkt->hdr.msg_type ==
|
|
||||||
nvsp_msg_1_type_send_rndis_pkt_complete) {
|
|
||||||
/* Get the send context */
|
|
||||||
net_vsc_pkt =
|
|
||||||
(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) {
|
|
||||||
u_long mask;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
idx = net_vsc_pkt->send_buf_section_idx /
|
|
||||||
BITS_PER_LONG;
|
|
||||||
KASSERT(idx < net_dev->bitsmap_words,
|
|
||||||
("invalid section index %u",
|
|
||||||
net_vsc_pkt->send_buf_section_idx));
|
|
||||||
mask = 1UL <<
|
|
||||||
(net_vsc_pkt->send_buf_section_idx %
|
|
||||||
BITS_PER_LONG);
|
|
||||||
|
|
||||||
KASSERT(net_dev->send_section_bitsmap[idx] &
|
|
||||||
mask,
|
|
||||||
("index bitmap 0x%lx, section index %u, "
|
|
||||||
"bitmap idx %d, bitmask 0x%lx",
|
|
||||||
net_dev->send_section_bitsmap[idx],
|
|
||||||
net_vsc_pkt->send_buf_section_idx,
|
|
||||||
idx, mask));
|
|
||||||
atomic_clear_long(
|
|
||||||
&net_dev->send_section_bitsmap[idx], mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notify the layer above us */
|
|
||||||
net_vsc_pkt->compl.send.on_send_completion(chan,
|
|
||||||
net_vsc_pkt->compl.send.send_completion_context);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -799,14 +802,14 @@ hv_nv_on_send_completion(netvsc_dev *net_dev, struct vmbus_channel *chan,
|
|||||||
* Returns 0 on success, non-zero on failure.
|
* Returns 0 on success, non-zero on failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
hv_nv_on_send(struct vmbus_channel *chan,
|
hv_nv_on_send(struct vmbus_channel *chan, bool is_data_pkt,
|
||||||
netvsc_packet *pkt, struct vmbus_gpa *gpa, int gpa_cnt)
|
struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
|
||||||
{
|
{
|
||||||
nvsp_msg send_msg;
|
nvsp_msg send_msg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt;
|
send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt;
|
||||||
if (pkt->is_data_pkt) {
|
if (is_data_pkt) {
|
||||||
/* 0 is RMC_DATA */
|
/* 0 is RMC_DATA */
|
||||||
send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0;
|
send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -815,17 +818,17 @@ hv_nv_on_send(struct vmbus_channel *chan,
|
|||||||
}
|
}
|
||||||
|
|
||||||
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
|
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
|
||||||
pkt->send_buf_section_idx;
|
sndc->hn_chim_idx;
|
||||||
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size =
|
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size =
|
||||||
pkt->send_buf_section_size;
|
sndc->hn_chim_sz;
|
||||||
|
|
||||||
if (gpa_cnt) {
|
if (gpa_cnt) {
|
||||||
ret = vmbus_chan_send_sglist(chan, gpa, gpa_cnt,
|
ret = vmbus_chan_send_sglist(chan, gpa, gpa_cnt,
|
||||||
&send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
|
&send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)sndc);
|
||||||
} else {
|
} else {
|
||||||
ret = vmbus_chan_send(chan,
|
ret = vmbus_chan_send(chan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
||||||
&send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
|
&send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)sndc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
|
@ -1112,29 +1112,8 @@ typedef void (*pfn_on_send_rx_completion)(struct vmbus_channel *, void *);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct netvsc_packet_ {
|
typedef struct netvsc_packet_ {
|
||||||
uint8_t is_data_pkt; /* One byte */
|
uint16_t vlan_tci;
|
||||||
uint16_t vlan_tci;
|
uint32_t status;
|
||||||
uint32_t status;
|
|
||||||
|
|
||||||
/* Completion */
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint64_t rx_completion_tid;
|
|
||||||
void *rx_completion_context;
|
|
||||||
/* This is no longer used */
|
|
||||||
pfn_on_send_rx_completion on_rx_completion;
|
|
||||||
} rx;
|
|
||||||
struct {
|
|
||||||
uint64_t send_completion_tid;
|
|
||||||
void *send_completion_context;
|
|
||||||
/* Still used in netvsc and filter code */
|
|
||||||
pfn_on_send_rx_completion on_send_completion;
|
|
||||||
} send;
|
|
||||||
} compl;
|
|
||||||
uint32_t send_buf_section_idx;
|
|
||||||
uint32_t send_buf_section_size;
|
|
||||||
|
|
||||||
void *rndis_mesg;
|
|
||||||
uint32_t tot_data_buf_len;
|
uint32_t tot_data_buf_len;
|
||||||
void *data;
|
void *data;
|
||||||
} netvsc_packet;
|
} netvsc_packet;
|
||||||
@ -1270,14 +1249,15 @@ typedef struct hn_softc {
|
|||||||
* Externs
|
* Externs
|
||||||
*/
|
*/
|
||||||
extern int hv_promisc_mode;
|
extern int hv_promisc_mode;
|
||||||
|
struct hn_send_ctx;
|
||||||
|
|
||||||
void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
|
void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
|
||||||
netvsc_dev *hv_nv_on_device_add(struct hn_softc *sc,
|
netvsc_dev *hv_nv_on_device_add(struct hn_softc *sc,
|
||||||
void *additional_info, struct hn_rx_ring *rxr);
|
void *additional_info, struct hn_rx_ring *rxr);
|
||||||
int hv_nv_on_device_remove(struct hn_softc *sc,
|
int hv_nv_on_device_remove(struct hn_softc *sc,
|
||||||
boolean_t destroy_channel);
|
boolean_t destroy_channel);
|
||||||
int hv_nv_on_send(struct vmbus_channel *chan, netvsc_packet *pkt,
|
int hv_nv_on_send(struct vmbus_channel *chan, bool is_data_pkt,
|
||||||
struct vmbus_gpa *gpa, int gpa_cnt);
|
struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt);
|
||||||
int hv_nv_get_next_send_section(netvsc_dev *net_dev);
|
int hv_nv_get_next_send_section(netvsc_dev *net_dev);
|
||||||
void hv_nv_subchan_attach(struct vmbus_channel *chan,
|
void hv_nv_subchan_attach(struct vmbus_channel *chan,
|
||||||
struct hn_rx_ring *rxr);
|
struct hn_rx_ring *rxr);
|
||||||
|
@ -166,7 +166,7 @@ struct hn_txdesc {
|
|||||||
struct hn_tx_ring *txr;
|
struct hn_tx_ring *txr;
|
||||||
int refs;
|
int refs;
|
||||||
uint32_t flags; /* HN_TXD_FLAG_ */
|
uint32_t flags; /* HN_TXD_FLAG_ */
|
||||||
netvsc_packet netvsc_pkt; /* XXX to be removed */
|
struct hn_send_ctx send_ctx;
|
||||||
|
|
||||||
bus_dmamap_t data_dmap;
|
bus_dmamap_t data_dmap;
|
||||||
|
|
||||||
@ -781,14 +781,14 @@ hn_txeof(struct hn_tx_ring *txr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hn_tx_done(struct vmbus_channel *chan, void *xpkt)
|
hn_tx_done(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
|
||||||
|
struct vmbus_channel *chan, const struct nvsp_msg_ *msg __unused)
|
||||||
{
|
{
|
||||||
netvsc_packet *packet = xpkt;
|
struct hn_txdesc *txd = sndc->hn_cbarg;
|
||||||
struct hn_txdesc *txd;
|
|
||||||
struct hn_tx_ring *txr;
|
struct hn_tx_ring *txr;
|
||||||
|
|
||||||
txd = (struct hn_txdesc *)(uintptr_t)
|
if (sndc->hn_chim_idx != NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX)
|
||||||
packet->compl.send.send_completion_tid;
|
hn_chim_free(net_dev, sndc->hn_chim_idx);
|
||||||
|
|
||||||
txr = txd->txr;
|
txr = txd->txr;
|
||||||
KASSERT(txr->hn_chan == chan,
|
KASSERT(txr->hn_chan == chan,
|
||||||
@ -835,16 +835,14 @@ hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
|
|||||||
bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
|
bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
|
||||||
int error, nsegs, i;
|
int error, nsegs, i;
|
||||||
struct mbuf *m_head = *m_head0;
|
struct mbuf *m_head = *m_head0;
|
||||||
netvsc_packet *packet;
|
|
||||||
rndis_msg *rndis_mesg;
|
rndis_msg *rndis_mesg;
|
||||||
rndis_packet *rndis_pkt;
|
rndis_packet *rndis_pkt;
|
||||||
rndis_per_packet_info *rppi;
|
rndis_per_packet_info *rppi;
|
||||||
struct rndis_hash_value *hash_value;
|
struct rndis_hash_value *hash_value;
|
||||||
uint32_t rndis_msg_size;
|
uint32_t rndis_msg_size, tot_data_buf_len, send_buf_section_idx;
|
||||||
|
int send_buf_section_size;
|
||||||
|
|
||||||
packet = &txd->netvsc_pkt;
|
tot_data_buf_len = m_head->m_pkthdr.len;
|
||||||
packet->is_data_pkt = TRUE;
|
|
||||||
packet->tot_data_buf_len = m_head->m_pkthdr.len;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extension points to the area reserved for the
|
* extension points to the area reserved for the
|
||||||
@ -859,7 +857,7 @@ hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
|
|||||||
|
|
||||||
rndis_pkt = &rndis_mesg->msg.packet;
|
rndis_pkt = &rndis_mesg->msg.packet;
|
||||||
rndis_pkt->data_offset = sizeof(rndis_packet);
|
rndis_pkt->data_offset = sizeof(rndis_packet);
|
||||||
rndis_pkt->data_length = packet->tot_data_buf_len;
|
rndis_pkt->data_length = tot_data_buf_len;
|
||||||
rndis_pkt->per_pkt_info_offset = sizeof(rndis_packet);
|
rndis_pkt->per_pkt_info_offset = sizeof(rndis_packet);
|
||||||
|
|
||||||
rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet);
|
rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet);
|
||||||
@ -967,15 +965,14 @@ hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rndis_mesg->msg_len = packet->tot_data_buf_len + rndis_msg_size;
|
rndis_mesg->msg_len = tot_data_buf_len + rndis_msg_size;
|
||||||
packet->tot_data_buf_len = rndis_mesg->msg_len;
|
tot_data_buf_len = rndis_mesg->msg_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Chimney send, if the packet could fit into one chimney buffer.
|
* Chimney send, if the packet could fit into one chimney buffer.
|
||||||
*/
|
*/
|
||||||
if (packet->tot_data_buf_len < txr->hn_tx_chimney_size) {
|
if (tot_data_buf_len < txr->hn_tx_chimney_size) {
|
||||||
netvsc_dev *net_dev = txr->hn_sc->net_dev;
|
netvsc_dev *net_dev = txr->hn_sc->net_dev;
|
||||||
uint32_t send_buf_section_idx;
|
|
||||||
|
|
||||||
txr->hn_tx_chimney_tried++;
|
txr->hn_tx_chimney_tried++;
|
||||||
send_buf_section_idx =
|
send_buf_section_idx =
|
||||||
@ -990,9 +987,7 @@ hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
|
|||||||
dest += rndis_msg_size;
|
dest += rndis_msg_size;
|
||||||
m_copydata(m_head, 0, m_head->m_pkthdr.len, dest);
|
m_copydata(m_head, 0, m_head->m_pkthdr.len, dest);
|
||||||
|
|
||||||
packet->send_buf_section_idx = send_buf_section_idx;
|
send_buf_section_size = tot_data_buf_len;
|
||||||
packet->send_buf_section_size =
|
|
||||||
packet->tot_data_buf_len;
|
|
||||||
txr->hn_gpa_cnt = 0;
|
txr->hn_gpa_cnt = 0;
|
||||||
txr->hn_tx_chimney++;
|
txr->hn_tx_chimney++;
|
||||||
goto done;
|
goto done;
|
||||||
@ -1039,16 +1034,14 @@ hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
|
|||||||
gpa->gpa_len = segs[i].ds_len;
|
gpa->gpa_len = segs[i].ds_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->send_buf_section_idx =
|
send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
|
||||||
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
|
send_buf_section_size = 0;
|
||||||
packet->send_buf_section_size = 0;
|
|
||||||
done:
|
done:
|
||||||
txd->m = m_head;
|
txd->m = m_head;
|
||||||
|
|
||||||
/* Set the completion routine */
|
/* Set the completion routine */
|
||||||
packet->compl.send.on_send_completion = hn_tx_done;
|
hn_send_ctx_init(&txd->send_ctx, hn_tx_done, txd,
|
||||||
packet->compl.send.send_completion_context = packet;
|
send_buf_section_idx, send_buf_section_size);
|
||||||
packet->compl.send.send_completion_tid = (uint64_t)(uintptr_t)txd;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1068,7 +1061,7 @@ again:
|
|||||||
* Make sure that txd is not freed before ETHER_BPF_MTAP.
|
* Make sure that txd is not freed before ETHER_BPF_MTAP.
|
||||||
*/
|
*/
|
||||||
hn_txdesc_hold(txd);
|
hn_txdesc_hold(txd);
|
||||||
error = hv_nv_on_send(txr->hn_chan, &txd->netvsc_pkt,
|
error = hv_nv_on_send(txr->hn_chan, true, &txd->send_ctx,
|
||||||
txr->hn_gpa, txr->hn_gpa_cnt);
|
txr->hn_gpa, txr->hn_gpa_cnt);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
ETHER_BPF_MTAP(ifp, txd->m);
|
ETHER_BPF_MTAP(ifp, txd->m);
|
||||||
|
@ -85,11 +85,17 @@ static int hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
|
|||||||
static int hv_rf_init_device(rndis_device *device);
|
static int hv_rf_init_device(rndis_device *device);
|
||||||
static int hv_rf_open_device(rndis_device *device);
|
static int hv_rf_open_device(rndis_device *device);
|
||||||
static int hv_rf_close_device(rndis_device *device);
|
static int hv_rf_close_device(rndis_device *device);
|
||||||
static void hv_rf_on_send_request_completion(struct vmbus_channel *, void *context);
|
|
||||||
static void hv_rf_on_send_request_halt_completion(struct vmbus_channel *, void *context);
|
|
||||||
int
|
int
|
||||||
hv_rf_send_offload_request(struct hn_softc *sc,
|
hv_rf_send_offload_request(struct hn_softc *sc,
|
||||||
rndis_offload_params *offloads);
|
rndis_offload_params *offloads);
|
||||||
|
|
||||||
|
static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
|
||||||
|
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
|
||||||
|
const struct nvsp_msg_ *msg);
|
||||||
|
static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
|
||||||
|
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
|
||||||
|
const struct nvsp_msg_ *msg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the Per-Packet-Info with the specified type
|
* Set the Per-Packet-Info with the specified type
|
||||||
*/
|
*/
|
||||||
@ -238,17 +244,14 @@ static int
|
|||||||
hv_rf_send_request(rndis_device *device, rndis_request *request,
|
hv_rf_send_request(rndis_device *device, rndis_request *request,
|
||||||
uint32_t message_type)
|
uint32_t message_type)
|
||||||
{
|
{
|
||||||
netvsc_packet *packet;
|
|
||||||
netvsc_dev *net_dev = device->net_dev;
|
netvsc_dev *net_dev = device->net_dev;
|
||||||
int send_buf_section_idx;
|
uint32_t send_buf_section_idx, tot_data_buf_len;
|
||||||
struct vmbus_gpa gpa[2];
|
struct vmbus_gpa gpa[2];
|
||||||
int gpa_cnt;
|
int gpa_cnt, send_buf_section_size;
|
||||||
|
hn_sent_callback_t cb;
|
||||||
|
|
||||||
/* Set up the packet to send it */
|
/* Set up the packet to send it */
|
||||||
packet = &request->pkt;
|
tot_data_buf_len = request->request_msg.msg_len;
|
||||||
|
|
||||||
packet->is_data_pkt = FALSE;
|
|
||||||
packet->tot_data_buf_len = request->request_msg.msg_len;
|
|
||||||
|
|
||||||
gpa_cnt = 1;
|
gpa_cnt = 1;
|
||||||
gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
|
gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
|
||||||
@ -265,16 +268,12 @@ hv_rf_send_request(rndis_device *device, rndis_request *request,
|
|||||||
gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
|
gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->compl.send.send_completion_context = request; /* packet */
|
if (message_type != REMOTE_NDIS_HALT_MSG)
|
||||||
if (message_type != REMOTE_NDIS_HALT_MSG) {
|
cb = hn_rndis_sent_cb;
|
||||||
packet->compl.send.on_send_completion =
|
else
|
||||||
hv_rf_on_send_request_completion;
|
cb = hn_rndis_sent_halt;
|
||||||
} else {
|
|
||||||
packet->compl.send.on_send_completion =
|
if (tot_data_buf_len < net_dev->send_section_size) {
|
||||||
hv_rf_on_send_request_halt_completion;
|
|
||||||
}
|
|
||||||
packet->compl.send.send_completion_tid = (unsigned long)device;
|
|
||||||
if (packet->tot_data_buf_len < net_dev->send_section_size) {
|
|
||||||
send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
|
send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
|
||||||
if (send_buf_section_idx !=
|
if (send_buf_section_idx !=
|
||||||
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
|
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
|
||||||
@ -282,19 +281,20 @@ hv_rf_send_request(rndis_device *device, rndis_request *request,
|
|||||||
send_buf_section_idx * net_dev->send_section_size);
|
send_buf_section_idx * net_dev->send_section_size);
|
||||||
|
|
||||||
memcpy(dest, &request->request_msg, request->request_msg.msg_len);
|
memcpy(dest, &request->request_msg, request->request_msg.msg_len);
|
||||||
packet->send_buf_section_idx = send_buf_section_idx;
|
send_buf_section_size = tot_data_buf_len;
|
||||||
packet->send_buf_section_size = packet->tot_data_buf_len;
|
|
||||||
gpa_cnt = 0;
|
gpa_cnt = 0;
|
||||||
goto sendit;
|
goto sendit;
|
||||||
}
|
}
|
||||||
/* Failed to allocate chimney send buffer; move on */
|
/* Failed to allocate chimney send buffer; move on */
|
||||||
}
|
}
|
||||||
packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
|
send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
|
||||||
packet->send_buf_section_size = 0;
|
send_buf_section_size = 0;
|
||||||
|
|
||||||
sendit:
|
sendit:
|
||||||
return hv_nv_on_send(device->net_dev->sc->hn_prichan, packet,
|
hn_send_ctx_init(&request->send_ctx, cb, request,
|
||||||
gpa, gpa_cnt);
|
send_buf_section_idx, send_buf_section_size);
|
||||||
|
return hv_nv_on_send(device->net_dev->sc->hn_prichan, false,
|
||||||
|
&request->send_ctx, gpa, gpa_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1056,6 +1056,7 @@ int
|
|||||||
hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
|
hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
|
||||||
int nchan, struct hn_rx_ring *rxr)
|
int nchan, struct hn_rx_ring *rxr)
|
||||||
{
|
{
|
||||||
|
struct hn_send_ctx sndc;
|
||||||
int ret;
|
int ret;
|
||||||
netvsc_dev *net_dev;
|
netvsc_dev *net_dev;
|
||||||
rndis_device *rndis_dev;
|
rndis_device *rndis_dev;
|
||||||
@ -1162,9 +1163,10 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
|
|||||||
init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
|
init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
|
||||||
net_dev->num_channel - 1;
|
net_dev->num_channel - 1;
|
||||||
|
|
||||||
|
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
|
||||||
ret = vmbus_chan_send(sc->hn_prichan,
|
ret = vmbus_chan_send(sc->hn_prichan,
|
||||||
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
|
||||||
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
|
init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
device_printf(dev, "Fail to allocate subchannel\n");
|
device_printf(dev, "Fail to allocate subchannel\n");
|
||||||
goto out;
|
goto out;
|
||||||
@ -1235,23 +1237,22 @@ hv_rf_on_close(struct hn_softc *sc)
|
|||||||
return (hv_rf_close_device((rndis_device *)net_dev->extension));
|
return (hv_rf_close_device((rndis_device *)net_dev->extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void
|
||||||
* RNDIS filter on send request completion callback
|
hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
|
||||||
*/
|
struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused)
|
||||||
static void
|
|
||||||
hv_rf_on_send_request_completion(struct vmbus_channel *chan __unused,
|
|
||||||
void *context __unused)
|
|
||||||
{
|
{
|
||||||
|
if (sndc->hn_chim_idx != NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX)
|
||||||
|
hn_chim_free(net_dev, sndc->hn_chim_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void
|
||||||
* RNDIS filter on send request (halt only) completion callback
|
hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
|
||||||
*/
|
struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused)
|
||||||
static void
|
|
||||||
hv_rf_on_send_request_halt_completion(struct vmbus_channel *chan __unused,
|
|
||||||
void *context)
|
|
||||||
{
|
{
|
||||||
rndis_request *request = context;
|
rndis_request *request = sndc->hn_cbarg;
|
||||||
|
|
||||||
|
if (sndc->hn_chim_idx != NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX)
|
||||||
|
hn_chim_free(net_dev, sndc->hn_chim_idx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notify hv_rf_halt_device() about halt completion.
|
* Notify hv_rf_halt_device() about halt completion.
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
|
#include <dev/hyperv/netvsc/if_hnvar.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defines
|
* Defines
|
||||||
@ -75,7 +76,7 @@ typedef struct rndis_request_ {
|
|||||||
uint8_t buf_resp[PAGE_SIZE];
|
uint8_t buf_resp[PAGE_SIZE];
|
||||||
|
|
||||||
/* Simplify allocation by having a netvsc packet inline */
|
/* Simplify allocation by having a netvsc packet inline */
|
||||||
netvsc_packet pkt;
|
struct hn_send_ctx send_ctx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The max request size is sizeof(rndis_msg) + PAGE_SIZE.
|
* The max request size is sizeof(rndis_msg) + PAGE_SIZE.
|
||||||
|
83
sys/dev/hyperv/netvsc/if_hnvar.h
Normal file
83
sys/dev/hyperv/netvsc/if_hnvar.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2016 Microsoft Corp.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice unmodified, this list of conditions, and the following
|
||||||
|
* disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IF_HNVAR_H_
|
||||||
|
#define _IF_HNVAR_H_
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <dev/hyperv/netvsc/hv_net_vsc.h>
|
||||||
|
|
||||||
|
struct netvsc_dev_;
|
||||||
|
struct nvsp_msg_;
|
||||||
|
|
||||||
|
struct vmbus_channel;
|
||||||
|
struct hn_send_ctx;
|
||||||
|
|
||||||
|
typedef void (*hn_sent_callback_t)
|
||||||
|
(struct hn_send_ctx *, struct netvsc_dev_ *,
|
||||||
|
struct vmbus_channel *, const struct nvsp_msg_ *);
|
||||||
|
|
||||||
|
struct hn_send_ctx {
|
||||||
|
hn_sent_callback_t hn_cb;
|
||||||
|
void *hn_cbarg;
|
||||||
|
uint32_t hn_chim_idx;
|
||||||
|
int hn_chim_sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HN_SEND_CTX_INITIALIZER(cb, cbarg) \
|
||||||
|
{ \
|
||||||
|
.hn_cb = cb, \
|
||||||
|
.hn_cbarg = cbarg, \
|
||||||
|
.hn_chim_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX, \
|
||||||
|
.hn_chim_sz = 0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
hn_send_ctx_init(struct hn_send_ctx *sndc, hn_sent_callback_t cb,
|
||||||
|
void *cbarg, uint32_t chim_idx, int chim_sz)
|
||||||
|
{
|
||||||
|
sndc->hn_cb = cb;
|
||||||
|
sndc->hn_cbarg = cbarg;
|
||||||
|
sndc->hn_chim_idx = chim_idx;
|
||||||
|
sndc->hn_chim_sz = chim_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
hn_send_ctx_init_simple(struct hn_send_ctx *sndc, hn_sent_callback_t cb,
|
||||||
|
void *cbarg)
|
||||||
|
{
|
||||||
|
hn_send_ctx_init(sndc, cb, cbarg,
|
||||||
|
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hn_nvs_sent_wakeup(struct hn_send_ctx *sndc,
|
||||||
|
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
|
||||||
|
const struct nvsp_msg_ *msg);
|
||||||
|
void hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx);
|
||||||
|
|
||||||
|
#endif /* !_IF_HNVAR_H_ */
|
Loading…
x
Reference in New Issue
Block a user