Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/hv_net_vsc.c
Show All 39 Lines | |||||
#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 "hv_net_vsc.h" | #include <dev/hyperv/include/vmbus_xact.h> | ||||
#include "hv_rndis.h" | #include <dev/hyperv/netvsc/hv_net_vsc.h> | ||||
#include "hv_rndis_filter.h" | #include <dev/hyperv/netvsc/hv_rndis.h> | ||||
#include <dev/hyperv/netvsc/hv_rndis_filter.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 *); | static int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *); | ||||
static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); | 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_destroy_rx_buffer(netvsc_dev *net_dev); | ||||
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(netvsc_dev *net_dev, | ||||
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, uint32_t status); | uint64_t tid, uint32_t status); | ||||
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 netvsc_dev_ *net_dev, struct vmbus_channel *chan, | ||||
const struct nvsp_msg_ *msg); | const struct nvsp_msg_ *msg, int); | ||||
static void hn_nvs_sent_xact(struct hn_send_ctx *sndc, | |||||
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan, | |||||
const struct nvsp_msg_ *msg, int dlen); | |||||
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); | ||||
/* | /* | ||||
* | * | ||||
*/ | */ | ||||
static inline netvsc_dev * | static inline netvsc_dev * | ||||
▲ Show 20 Lines • Show All 375 Lines • ▼ Show 20 Lines | hv_nv_destroy_send_buffer(netvsc_dev *net_dev) | ||||
if (net_dev->send_section_bitsmap) { | if (net_dev->send_section_bitsmap) { | ||||
free(net_dev->send_section_bitsmap, M_NETVSC); | free(net_dev->send_section_bitsmap, M_NETVSC); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | |||||
* Attempt to negotiate the caller-specified NVSP version | |||||
* | |||||
* For NVSP v2, Server 2008 R2 does not set | |||||
* init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers | |||||
* to the negotiated version, so we cannot rely on that. | |||||
*/ | |||||
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 nvsp_ver) | uint32_t nvs_ver) | ||||
{ | { | ||||
struct hn_send_ctx sndc; | struct hn_send_ctx sndc; | ||||
nvsp_msg *init_pkt; | struct vmbus_xact *xact; | ||||
int ret; | struct hn_nvs_init *init; | ||||
const struct hn_nvs_init_resp *resp; | |||||
size_t resp_len; | |||||
uint32_t status; | |||||
int error; | |||||
init_pkt = &net_dev->channel_init_packet; | xact = vmbus_xact_get(sc->hn_xact, sizeof(*init)); | ||||
memset(init_pkt, 0, sizeof(nvsp_msg)); | if (xact == NULL) { | ||||
init_pkt->hdr.msg_type = nvsp_msg_type_init; | if_printf(sc->hn_ifp, "no xact for nvs init\n"); | ||||
return (ENXIO); | |||||
} | |||||
/* | init = vmbus_xact_req_data(xact); | ||||
* Specify parameter as the only acceptable protocol version | init->nvs_type = HN_NVS_TYPE_INIT; | ||||
*/ | init->nvs_ver_min = nvs_ver; | ||||
init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver; | init->nvs_ver_max = nvs_ver; | ||||
init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver; | |||||
/* Send the init request */ | vmbus_xact_activate(xact); | ||||
hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL); | hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact); | ||||
ret = vmbus_chan_send(sc->hn_prichan, | |||||
error = 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)&sndc); | init, sizeof(*init), (uint64_t)(uintptr_t)&sndc); | ||||
if (ret != 0) | if (error) { | ||||
return (-1); | if_printf(sc->hn_ifp, "send nvs init failed: %d\n", error); | ||||
vmbus_xact_deactivate(xact); | |||||
vmbus_xact_put(xact); | |||||
return (error); | |||||
} | |||||
sema_wait(&net_dev->channel_init_sema); | resp = vmbus_xact_wait(xact, &resp_len); | ||||
if (resp_len < sizeof(*resp)) { | |||||
if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success) | if_printf(sc->hn_ifp, "invalid init resp length %zu\n", | ||||
resp_len); | |||||
vmbus_xact_put(xact); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | |||||
if (resp->nvs_type != HN_NVS_TYPE_INIT_RESP) { | |||||
if_printf(sc->hn_ifp, "not init resp, type %u\n", | |||||
resp->nvs_type); | |||||
vmbus_xact_put(xact); | |||||
return (EINVAL); | |||||
} | |||||
status = resp->nvs_status; | |||||
vmbus_xact_put(xact); | |||||
if (status != HN_NVS_STATUS_OK) { | |||||
if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n", | |||||
nvs_ver); | |||||
return (EINVAL); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Send NDIS version 2 config packet containing MTU. | * Send NDIS version 2 config packet containing MTU. | ||||
* | * | ||||
* Not valid for NDIS version 1. | * Not valid for NDIS version 1. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel) | ||||
free(net_dev, M_NETVSC); | free(net_dev, M_NETVSC); | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
hn_nvs_sent_wakeup(struct hn_send_ctx *sndc __unused, | hn_nvs_sent_wakeup(struct hn_send_ctx *sndc __unused, | ||||
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan __unused, | struct netvsc_dev_ *net_dev, struct vmbus_channel *chan __unused, | ||||
const struct nvsp_msg_ *msg) | const struct nvsp_msg_ *msg, int dlen __unused) | ||||
{ | { | ||||
/* Copy the response back */ | /* Copy the response back */ | ||||
memcpy(&net_dev->channel_init_packet, msg, sizeof(nvsp_msg)); | memcpy(&net_dev->channel_init_packet, msg, sizeof(nvsp_msg)); | ||||
sema_post(&net_dev->channel_init_sema); | sema_post(&net_dev->channel_init_sema); | ||||
} | } | ||||
static void | static void | ||||
hn_nvs_sent_xact(struct hn_send_ctx *sndc, | |||||
struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused, | |||||
const struct nvsp_msg_ *msg, int dlen) | |||||
{ | |||||
vmbus_xact_wakeup(sndc->hn_cbarg, msg, dlen); | |||||
} | |||||
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 netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused, | ||||
const struct nvsp_msg_ *msg __unused) | const struct nvsp_msg_ *msg __unused, int dlen __unused) | ||||
{ | { | ||||
/* EMPTY */ | /* EMPTY */ | ||||
} | } | ||||
void | void | ||||
hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx) | hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx) | ||||
{ | { | ||||
u_long mask; | u_long mask; | ||||
Show All 17 Lines | |||||
*/ | */ | ||||
static void | 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) | ||||
{ | { | ||||
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, net_dev, chan, VMBUS_CHANPKT_CONST_DATA(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 244 Lines • Show Last 20 Lines |