Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/hv_net_vsc.c
Show All 31 Lines | |||||
* HyperV vmbus network VSC (virtual services client) module | * HyperV vmbus network VSC (virtual services client) module | ||||
* | * | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/limits.h> | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_arp.h> | #include <net/if_arp.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include <dev/hyperv/include/hyperv.h> | #include <dev/hyperv/include/hyperv.h> | ||||
#include <dev/hyperv/include/vmbus_xact.h> | #include <dev/hyperv/include/vmbus_xact.h> | ||||
#include <dev/hyperv/netvsc/hv_net_vsc.h> | #include <dev/hyperv/netvsc/hv_net_vsc.h> | ||||
#include <dev/hyperv/netvsc/hv_rndis.h> | #include <dev/hyperv/netvsc/hv_rndis.h> | ||||
#include <dev/hyperv/netvsc/hv_rndis_filter.h> | #include <dev/hyperv/netvsc/hv_rndis_filter.h> | ||||
#include <dev/hyperv/netvsc/if_hnreg.h> | #include <dev/hyperv/netvsc/if_hnreg.h> | ||||
MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); | MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); | ||||
/* | /* | ||||
* Forward declarations | * Forward declarations | ||||
*/ | */ | ||||
static void hv_nv_on_channel_callback(struct vmbus_channel *chan, | static void hv_nv_on_channel_callback(struct vmbus_channel *chan, | ||||
void *xrxr); | void *xrxr); | ||||
static int hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc); | static int hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc); | ||||
static int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *, int); | static int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *, int); | ||||
static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); | static int hv_nv_destroy_send_buffer(struct hn_softc *sc); | ||||
static int hv_nv_destroy_rx_buffer(struct hn_softc *sc); | static int hv_nv_destroy_rx_buffer(struct hn_softc *sc); | ||||
static int hv_nv_connect_to_vsp(struct hn_softc *sc); | static int hv_nv_connect_to_vsp(struct hn_softc *sc); | ||||
static void hv_nv_on_send_completion(netvsc_dev *net_dev, | static void hv_nv_on_send_completion(struct hn_softc *sc, | ||||
struct vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt); | struct vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt); | ||||
static void hv_nv_on_receive_completion(struct vmbus_channel *chan, | static void hv_nv_on_receive_completion(struct vmbus_channel *chan, | ||||
uint64_t tid); | uint64_t tid); | ||||
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, | static void hn_nvs_sent_none(struct hn_send_ctx *sndc, | ||||
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan, | struct hn_softc *, struct vmbus_channel *chan, | ||||
const void *, int); | const void *, int); | ||||
static struct hn_send_ctx hn_send_ctx_none = | static struct hn_send_ctx hn_send_ctx_none = | ||||
HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL); | HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL); | ||||
/* | /* | ||||
* | * | ||||
*/ | */ | ||||
Show All 23 Lines | |||||
* XXX unnecessary; nuke it. | * XXX unnecessary; nuke it. | ||||
*/ | */ | ||||
static inline netvsc_dev * | static inline netvsc_dev * | ||||
hv_nv_get_inbound_net_device(struct hn_softc *sc) | hv_nv_get_inbound_net_device(struct hn_softc *sc) | ||||
{ | { | ||||
return sc->net_dev; | return sc->net_dev; | ||||
} | } | ||||
int | uint32_t | ||||
hv_nv_get_next_send_section(netvsc_dev *net_dev) | hn_chim_alloc(struct hn_softc *sc) | ||||
{ | { | ||||
unsigned long bitsmap_words = net_dev->bitsmap_words; | int i, bmap_cnt = sc->hn_chim_bmap_cnt; | ||||
unsigned long *bitsmap = net_dev->send_section_bitsmap; | u_long *bmap = sc->hn_chim_bmap; | ||||
unsigned long idx; | uint32_t ret = HN_NVS_CHIM_IDX_INVALID; | ||||
int ret = HN_NVS_CHIM_IDX_INVALID; | |||||
int i; | |||||
for (i = 0; i < bitsmap_words; i++) { | for (i = 0; i < bmap_cnt; ++i) { | ||||
idx = ffsl(~bitsmap[i]); | int idx; | ||||
if (0 == idx) | |||||
idx = ffsl(~bmap[i]); | |||||
if (idx == 0) | |||||
continue; | continue; | ||||
idx--; | --idx; /* ffsl is 1-based */ | ||||
KASSERT(i * BITS_PER_LONG + idx < net_dev->send_section_count, | KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, | ||||
("invalid i %d and idx %lu", i, idx)); | ("invalid i %d and idx %d", i, idx)); | ||||
if (atomic_testandset_long(&bitsmap[i], idx)) | if (atomic_testandset_long(&bmap[i], idx)) | ||||
continue; | continue; | ||||
ret = i * BITS_PER_LONG + idx; | ret = i * LONG_BIT + idx; | ||||
break; | break; | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | /* | ||||
* Net VSC initialize receive buffer with net VSP | * Net VSC initialize receive buffer with net VSP | ||||
* | * | ||||
* Net VSP: Network virtual services client, also known as the | * Net VSP: Network virtual services client, also known as the | ||||
* Hyper-V extensible switch and the synthetic data path. | * Hyper-V extensible switch and the synthetic data path. | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
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; | struct hn_send_ctx sndc; | ||||
struct vmbus_xact *xact; | struct vmbus_xact *xact; | ||||
struct hn_nvs_chim_conn *chim; | struct hn_nvs_chim_conn *chim; | ||||
const struct hn_nvs_chim_connresp *resp; | const struct hn_nvs_chim_connresp *resp; | ||||
size_t resp_len; | size_t resp_len; | ||||
uint32_t status, sectsz; | uint32_t status, sectsz; | ||||
netvsc_dev *net_dev; | |||||
int error; | int error; | ||||
net_dev = hv_nv_get_outbound_net_device(sc); | |||||
if (!net_dev) { | |||||
return (ENODEV); | |||||
} | |||||
net_dev->send_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), | |||||
PAGE_SIZE, 0, net_dev->send_buf_size, &net_dev->txbuf_dma, | |||||
BUS_DMA_WAITOK | BUS_DMA_ZERO); | |||||
if (net_dev->send_buf == NULL) { | |||||
device_printf(sc->hn_dev, "allocate chimney txbuf failed\n"); | |||||
return (ENOMEM); | |||||
} | |||||
/* | /* | ||||
* Connect chimney sending buffer GPADL to the primary channel. | * Connect chimney sending buffer GPADL to the primary channel. | ||||
* | * | ||||
* NOTE: | * NOTE: | ||||
* Only primary channel has chimney sending buffer connected to it. | * Only primary channel has chimney sending buffer connected to it. | ||||
* Sub-channels just share this chimney sending buffer. | * Sub-channels just share this chimney sending buffer. | ||||
*/ | */ | ||||
error = vmbus_chan_gpadl_connect(sc->hn_prichan, | error = vmbus_chan_gpadl_connect(sc->hn_prichan, | ||||
net_dev->txbuf_dma.hv_paddr, net_dev->send_buf_size, | sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE, | ||||
&net_dev->send_buf_gpadl_handle); | &sc->hn_chim_gpadl); | ||||
if (error) { | if (error) { | ||||
if_printf(sc->hn_ifp, "chimney sending buffer gpadl " | if_printf(sc->hn_ifp, "chimney sending buffer gpadl " | ||||
"connect failed: %d\n", error); | "connect failed: %d\n", error); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
/* | /* | ||||
* Connect chimney sending buffer to NVS | * Connect chimney sending buffer to NVS | ||||
*/ | */ | ||||
xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim)); | xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim)); | ||||
if (xact == NULL) { | if (xact == NULL) { | ||||
if_printf(sc->hn_ifp, "no xact for nvs chim conn\n"); | if_printf(sc->hn_ifp, "no xact for nvs chim conn\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
chim = vmbus_xact_req_data(xact); | chim = vmbus_xact_req_data(xact); | ||||
chim->nvs_type = HN_NVS_TYPE_CHIM_CONN; | chim->nvs_type = HN_NVS_TYPE_CHIM_CONN; | ||||
chim->nvs_gpadl = net_dev->send_buf_gpadl_handle; | chim->nvs_gpadl = sc->hn_chim_gpadl; | ||||
chim->nvs_sig = HN_NVS_CHIM_SIG; | chim->nvs_sig = HN_NVS_CHIM_SIG; | ||||
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact); | hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact); | ||||
vmbus_xact_activate(xact); | vmbus_xact_activate(xact); | ||||
error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC, | error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC, | ||||
chim, sizeof(*chim), &sndc); | chim, sizeof(*chim), &sndc); | ||||
if (error) { | if (error) { | ||||
Show All 30 Lines | if (status != HN_NVS_STATUS_OK) { | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (sectsz == 0) { | if (sectsz == 0) { | ||||
if_printf(sc->hn_ifp, "zero chimney sending buffer " | if_printf(sc->hn_ifp, "zero chimney sending buffer " | ||||
"section size\n"); | "section size\n"); | ||||
return 0; | return 0; | ||||
} | } | ||||
net_dev->send_section_size = sectsz; | sc->hn_chim_szmax = sectsz; | ||||
net_dev->send_section_count = | sc->hn_chim_cnt = NETVSC_SEND_BUFFER_SIZE / sc->hn_chim_szmax; | ||||
net_dev->send_buf_size / net_dev->send_section_size; | if (NETVSC_SEND_BUFFER_SIZE % sc->hn_chim_szmax != 0) { | ||||
net_dev->bitsmap_words = howmany(net_dev->send_section_count, | if_printf(sc->hn_ifp, "chimney sending sections are " | ||||
BITS_PER_LONG); | "not properly aligned\n"); | ||||
net_dev->send_section_bitsmap = | } | ||||
malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, | if (sc->hn_chim_cnt % LONG_BIT != 0) { | ||||
M_WAITOK | M_ZERO); | if_printf(sc->hn_ifp, "discard %d chimney sending sections\n", | ||||
sc->hn_chim_cnt % LONG_BIT); | |||||
} | |||||
sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT; | |||||
sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long), | |||||
M_NETVSC, M_WAITOK | M_ZERO); | |||||
/* Done! */ | |||||
sc->hn_flags |= HN_FLAG_CHIM_CONNECTED; | |||||
if (bootverbose) { | if (bootverbose) { | ||||
if_printf(sc->hn_ifp, "chimney sending buffer %u/%u\n", | if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n", | ||||
net_dev->send_section_size, net_dev->send_section_count); | sc->hn_chim_szmax, sc->hn_chim_cnt); | ||||
} | } | ||||
return 0; | return 0; | ||||
cleanup: | cleanup: | ||||
hv_nv_destroy_send_buffer(net_dev); | hv_nv_destroy_send_buffer(sc); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Net VSC destroy receive buffer | * Net VSC destroy receive buffer | ||||
*/ | */ | ||||
static int | static int | ||||
hv_nv_destroy_rx_buffer(struct hn_softc *sc) | hv_nv_destroy_rx_buffer(struct hn_softc *sc) | ||||
{ | { | ||||
int ret = 0; | int ret = 0; | ||||
if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) { | if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) { | ||||
struct hn_nvs_rxbuf_disconn disconn; | struct hn_nvs_rxbuf_disconn disconn; | ||||
/* | /* | ||||
* Disconnect RXBUF from NVS. | * Disconnect RXBUF from NVS. | ||||
*/ | */ | ||||
memset(&disconn, 0, sizeof(disconn)); | memset(&disconn, 0, sizeof(disconn)); | ||||
disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN; | disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN; | ||||
disconn.nvs_sig = HN_NVS_RXBUF_SIG; | disconn.nvs_sig = HN_NVS_RXBUF_SIG; | ||||
/* NOTE: No response. */ | /* NOTE: No response. */ | ||||
ret = hn_nvs_send(sc->hn_prichan, | ret = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE, | ||||
VMBUS_CHANPKT_FLAG_NONE, &disconn, sizeof(disconn), | &disconn, sizeof(disconn), &hn_send_ctx_none); | ||||
&hn_send_ctx_none); | |||||
if (ret != 0) { | if (ret != 0) { | ||||
if_printf(sc->hn_ifp, | if_printf(sc->hn_ifp, | ||||
"send rxbuf disconn failed: %d\n", ret); | "send rxbuf disconn failed: %d\n", ret); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; | sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; | ||||
} | } | ||||
Show All 12 Lines | hv_nv_destroy_rx_buffer(struct hn_softc *sc) | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | /* | ||||
* Net VSC destroy send buffer | * Net VSC destroy send buffer | ||||
*/ | */ | ||||
static int | static int | ||||
hv_nv_destroy_send_buffer(netvsc_dev *net_dev) | hv_nv_destroy_send_buffer(struct hn_softc *sc) | ||||
{ | { | ||||
int ret = 0; | int ret = 0; | ||||
if (net_dev->send_section_size) { | if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) { | ||||
struct hn_nvs_chim_disconn disconn; | struct hn_nvs_chim_disconn disconn; | ||||
/* | /* | ||||
* Disconnect chimney sending buffer from NVS. | * Disconnect chimney sending buffer from NVS. | ||||
*/ | */ | ||||
memset(&disconn, 0, sizeof(disconn)); | memset(&disconn, 0, sizeof(disconn)); | ||||
disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN; | disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN; | ||||
disconn.nvs_sig = HN_NVS_CHIM_SIG; | disconn.nvs_sig = HN_NVS_CHIM_SIG; | ||||
/* NOTE: No response. */ | /* NOTE: No response. */ | ||||
ret = hn_nvs_send(net_dev->sc->hn_prichan, | ret = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE, | ||||
VMBUS_CHANPKT_FLAG_NONE, &disconn, sizeof(disconn), | &disconn, sizeof(disconn), &hn_send_ctx_none); | ||||
&hn_send_ctx_none); | |||||
if (ret != 0) { | if (ret != 0) { | ||||
if_printf(net_dev->sc->hn_ifp, | if_printf(sc->hn_ifp, | ||||
"send chim disconn failed: %d\n", ret); | "send chim disconn failed: %d\n", ret); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED; | |||||
} | } | ||||
/* Tear down the gpadl on the vsp end */ | if (sc->hn_chim_gpadl != 0) { | ||||
if (net_dev->send_buf_gpadl_handle) { | |||||
ret = vmbus_chan_gpadl_disconnect(net_dev->sc->hn_prichan, | |||||
net_dev->send_buf_gpadl_handle); | |||||
/* | /* | ||||
* If we failed here, we might as well return and have a leak | * Disconnect chimney sending buffer from primary channel. | ||||
* rather than continue and a bugchk | |||||
*/ | */ | ||||
ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan, | |||||
sc->hn_chim_gpadl); | |||||
if (ret != 0) { | if (ret != 0) { | ||||
if_printf(sc->hn_ifp, | |||||
"chim disconn failed: %d\n", ret); | |||||
return (ret); | return (ret); | ||||
} | } | ||||
net_dev->send_buf_gpadl_handle = 0; | sc->hn_chim_gpadl = 0; | ||||
} | } | ||||
if (net_dev->send_buf) { | if (sc->hn_chim_bmap != NULL) { | ||||
/* Free up the receive buffer */ | free(sc->hn_chim_bmap, M_NETVSC); | ||||
hyperv_dmamem_free(&net_dev->txbuf_dma, net_dev->send_buf); | sc->hn_chim_bmap = NULL; | ||||
net_dev->send_buf = NULL; | |||||
} | } | ||||
if (net_dev->send_section_bitsmap) { | |||||
free(net_dev->send_section_bitsmap, M_NETVSC); | |||||
} | |||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | 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 nvs_ver) | uint32_t nvs_ver) | ||||
{ | { | ||||
struct hn_send_ctx sndc; | struct hn_send_ctx sndc; | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | if (ret != 0) { | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
/* Post the big receive buffer to NetVSP */ | /* Post the big receive buffer to NetVSP */ | ||||
if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_2) | if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_2) | ||||
rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; | rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; | ||||
else | else | ||||
rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE; | rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE; | ||||
net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; | |||||
ret = hv_nv_init_rx_buffer_with_net_vsp(sc, rxbuf_size); | ret = hv_nv_init_rx_buffer_with_net_vsp(sc, rxbuf_size); | ||||
if (ret == 0) | if (ret == 0) | ||||
ret = hv_nv_init_send_buffer_with_net_vsp(sc); | ret = hv_nv_init_send_buffer_with_net_vsp(sc); | ||||
cleanup: | cleanup: | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | /* | ||||
* Net VSC disconnect from VSP | * Net VSC disconnect from VSP | ||||
*/ | */ | ||||
static void | static void | ||||
hv_nv_disconnect_from_vsp(struct hn_softc *sc) | hv_nv_disconnect_from_vsp(struct hn_softc *sc) | ||||
{ | { | ||||
hv_nv_destroy_rx_buffer(sc); | hv_nv_destroy_rx_buffer(sc); | ||||
hv_nv_destroy_send_buffer(sc->net_dev); | hv_nv_destroy_send_buffer(sc); | ||||
} | } | ||||
void | void | ||||
hv_nv_subchan_attach(struct vmbus_channel *chan, struct hn_rx_ring *rxr) | hv_nv_subchan_attach(struct vmbus_channel *chan, struct hn_rx_ring *rxr) | ||||
{ | { | ||||
KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan), | KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan), | ||||
("chan%u subidx %u, rxr%d mismatch", | ("chan%u subidx %u, rxr%d mismatch", | ||||
vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx)); | vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx)); | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel) | ||||
free(sc->net_dev, M_NETVSC); | free(sc->net_dev, M_NETVSC); | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
hn_nvs_sent_xact(struct hn_send_ctx *sndc, | hn_nvs_sent_xact(struct hn_send_ctx *sndc, | ||||
struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused, | struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, | ||||
const void *data, int dlen) | const void *data, int dlen) | ||||
{ | { | ||||
vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen); | vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen); | ||||
} | } | ||||
static void | static void | ||||
hn_nvs_sent_none(struct hn_send_ctx *sndc __unused, | hn_nvs_sent_none(struct hn_send_ctx *sndc __unused, | ||||
struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused, | struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, | ||||
const void *data __unused, int dlen __unused) | const void *data __unused, int dlen __unused) | ||||
{ | { | ||||
/* EMPTY */ | /* EMPTY */ | ||||
} | } | ||||
void | void | ||||
hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx) | hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) | ||||
{ | { | ||||
u_long mask; | u_long mask; | ||||
uint32_t idx; | uint32_t idx; | ||||
idx = chim_idx / BITS_PER_LONG; | idx = chim_idx / LONG_BIT; | ||||
KASSERT(idx < net_dev->bitsmap_words, | KASSERT(idx < sc->hn_chim_bmap_cnt, | ||||
("invalid chimney index 0x%x", chim_idx)); | ("invalid chimney index 0x%x", chim_idx)); | ||||
mask = 1UL << (chim_idx % BITS_PER_LONG); | mask = 1UL << (chim_idx % LONG_BIT); | ||||
KASSERT(net_dev->send_section_bitsmap[idx] & mask, | KASSERT(sc->hn_chim_bmap[idx] & mask, | ||||
("index bitmap 0x%lx, chimney index %u, " | ("index bitmap 0x%lx, chimney index %u, " | ||||
"bitmap idx %d, bitmask 0x%lx", | "bitmap idx %d, bitmask 0x%lx", | ||||
net_dev->send_section_bitsmap[idx], chim_idx, idx, mask)); | sc->hn_chim_bmap[idx], chim_idx, idx, mask)); | ||||
atomic_clear_long(&net_dev->send_section_bitsmap[idx], mask); | atomic_clear_long(&sc->hn_chim_bmap[idx], mask); | ||||
} | } | ||||
/* | /* | ||||
* Net VSC on send completion | * Net VSC on send completion | ||||
*/ | */ | ||||
static void | static void | ||||
hv_nv_on_send_completion(netvsc_dev *net_dev, struct vmbus_channel *chan, | hv_nv_on_send_completion(struct hn_softc *sc, struct vmbus_channel *chan, | ||||
const struct vmbus_chanpkt_hdr *pkt) | const struct vmbus_chanpkt_hdr *pkt) | ||||
{ | { | ||||
struct hn_send_ctx *sndc; | struct hn_send_ctx *sndc; | ||||
sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid; | sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid; | ||||
sndc->hn_cb(sndc, net_dev, chan, VMBUS_CHANPKT_CONST_DATA(pkt), | sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), | ||||
VMBUS_CHANPKT_DATALEN(pkt)); | VMBUS_CHANPKT_DATALEN(pkt)); | ||||
/* | /* | ||||
* NOTE: | * NOTE: | ||||
* 'sndc' CAN NOT be accessed anymore, since it can be freed by | * 'sndc' CAN NOT be accessed anymore, since it can be freed by | ||||
* its callback. | * its callback. | ||||
*/ | */ | ||||
} | } | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | do { | ||||
int ret; | int ret; | ||||
bytes_rxed = bufferlen; | bytes_rxed = bufferlen; | ||||
ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); | ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); | ||||
if (ret == 0) { | if (ret == 0) { | ||||
if (bytes_rxed > 0) { | if (bytes_rxed > 0) { | ||||
switch (pkt->cph_type) { | switch (pkt->cph_type) { | ||||
case VMBUS_CHANPKT_TYPE_COMP: | case VMBUS_CHANPKT_TYPE_COMP: | ||||
hv_nv_on_send_completion(net_dev, chan, | hv_nv_on_send_completion(sc, chan, pkt); | ||||
pkt); | |||||
break; | break; | ||||
case VMBUS_CHANPKT_TYPE_RXBUF: | case VMBUS_CHANPKT_TYPE_RXBUF: | ||||
hv_nv_on_receive(net_dev, rxr, chan, pkt); | hv_nv_on_receive(net_dev, rxr, chan, pkt); | ||||
break; | break; | ||||
case VMBUS_CHANPKT_TYPE_INBAND: | case VMBUS_CHANPKT_TYPE_INBAND: | ||||
hn_proc_notify(sc, pkt); | hn_proc_notify(sc, pkt); | ||||
break; | break; | ||||
default: | default: | ||||
Show All 34 Lines |