summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/netvsc
diff options
context:
space:
mode:
authorsephe <sephe@FreeBSD.org>2016-10-17 07:27:16 +0000
committersephe <sephe@FreeBSD.org>2016-10-17 07:27:16 +0000
commit6830df8d176de91376b918186766be01f4133a7e (patch)
treef8136818ae1fcdd3c1c11fd8bc489988b47a7c16 /sys/dev/hyperv/netvsc
parent1650850a80f32eee2676cb7f8869df4e1d051ed8 (diff)
downloadFreeBSD-src-6830df8d176de91376b918186766be01f4133a7e.zip
FreeBSD-src-6830df8d176de91376b918186766be01f4133a7e.tar.gz
MFC 304973,304975,304976,304979,305044-305048
304973 hyperv/hn: Switch to new RNDIS query for link status extraction. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7654 304975 hyperv/hn: Switch to new RNDIS query for RSS capabilities extraction. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7656 304976 hyperv/hn: Fix # of channels setting, if RSS is not available. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7657 304979 hyperv/hn: Switch to new RNDIS set for RSS parameters. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7658 305044 hyperv/hn: Move OIDs to net/rndis.h; they are standard NDIS OIDs. Actually all OIDs defined in net/rndis.h are standard NDIS OIDs. While I'm here, use the verbose macro name as in NDIS spec. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7679 305045 hyperv/hn: Indentation and field comment fixup for ndis.h. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7680 305046 net/rndis: Packet types are defined by NDIS; not RNDIS specific. Reviewed by: hps Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7681 305047 hyperv/hn: Switch to new RNDIS set for RX filters. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7683 305048 hyperv/hn: Remove unused function Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7684
Diffstat (limited to 'sys/dev/hyperv/netvsc')
-rw-r--r--sys/dev/hyperv/netvsc/hv_net_vsc.h4
-rw-r--r--sys/dev/hyperv/netvsc/hv_rndis.h27
-rw-r--r--sys/dev/hyperv/netvsc/hv_rndis_filter.c559
-rw-r--r--sys/dev/hyperv/netvsc/ndis.h207
4 files changed, 317 insertions, 480 deletions
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h
index f51fe76..16fbef0 100644
--- a/sys/dev/hyperv/netvsc/hv_net_vsc.h
+++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h
@@ -62,6 +62,8 @@
#include <dev/hyperv/include/hyperv_busdma.h>
#include <dev/hyperv/include/vmbus.h>
+#include <dev/hyperv/netvsc/ndis.h>
+
#define HN_USE_TXDESC_BUFRING
MALLOC_DECLARE(M_NETVSC);
@@ -383,6 +385,8 @@ typedef struct hn_softc {
uint32_t hn_rndis_rid;
uint32_t hn_ndis_ver;
+
+ struct ndis_rssprm_toeplitz hn_rss;
} hn_softc_t;
#define HN_FLAG_RXBUF_CONNECTED 0x0001
diff --git a/sys/dev/hyperv/netvsc/hv_rndis.h b/sys/dev/hyperv/netvsc/hv_rndis.h
index a5e28f1..6524340 100644
--- a/sys/dev/hyperv/netvsc/hv_rndis.h
+++ b/sys/dev/hyperv/netvsc/hv_rndis.h
@@ -536,20 +536,6 @@ struct rndis_hash_info {
uint32_t hash_info;
} __packed;
-#define NDIS_HASH_FUNCTION_MASK 0x000000FF /* see hash function */
-#define NDIS_HASH_TYPE_MASK 0x00FFFF00 /* see hash type */
-
-/* hash function */
-#define NDIS_HASH_FUNCTION_TOEPLITZ 0x00000001
-
-/* hash type */
-#define NDIS_HASH_IPV4 0x00000100
-#define NDIS_HASH_TCP_IPV4 0x00000200
-#define NDIS_HASH_IPV6 0x00000400
-#define NDIS_HASH_IPV6_EX 0x00000800
-#define NDIS_HASH_TCP_IPV6 0x00001000
-#define NDIS_HASH_TCP_IPV6_EX 0x00002000
-
typedef struct rndis_tcp_tso_info_ {
union {
struct {
@@ -903,19 +889,6 @@ typedef struct rndismp_rx_bufs_info_ {
#define RNDIS_HEADER_SIZE (sizeof(rndis_msg) - sizeof(rndis_msg_container))
-#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
-#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
-#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
-#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
-#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
-#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
-#define NDIS_PACKET_TYPE_SMT 0x00000040
-#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
-#define NDIS_PACKET_TYPE_GROUP 0x00000100
-#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
-#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
-#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
-
/*
* Externs
*/
diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
index ae44243..b7aa303 100644
--- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c
+++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
@@ -79,17 +79,9 @@ static void hv_rf_receive_indicate_status(rndis_device *device,
const rndis_msg *response);
static void hv_rf_receive_data(struct hn_rx_ring *rxr,
const void *data, int dlen);
-static int hv_rf_query_device(rndis_device *device, uint32_t oid,
- void *result, uint32_t *result_size);
static inline int hv_rf_query_device_mac(rndis_device *device);
static inline int hv_rf_query_device_link_status(rndis_device *device);
-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_open_device(rndis_device *device);
-static int hv_rf_close_device(rndis_device *device);
-int
-hv_rf_send_offload_request(struct hn_softc *sc,
- rndis_offload_params *offloads);
static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
struct hn_softc *sc, struct vmbus_channel *chan,
@@ -102,6 +94,8 @@ static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
size_t dlen);
static int hn_rndis_conf_offload(struct hn_softc *sc);
+static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
+static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
static __inline uint32_t
hn_rndis_rid(struct hn_softc *sc)
@@ -355,78 +349,6 @@ hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
}
}
-int
-hv_rf_send_offload_request(struct hn_softc *sc,
- rndis_offload_params *offloads)
-{
- rndis_request *request;
- rndis_set_request *set;
- rndis_offload_params *offload_req;
- rndis_set_complete *set_complete;
- rndis_device *rndis_dev = sc->rndis_dev;
- device_t dev = sc->hn_dev;
- uint32_t extlen = sizeof(rndis_offload_params);
- int ret;
-
- if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_4) {
- extlen = VERSION_4_OFFLOAD_SIZE;
- /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
- * UDP checksum offload.
- */
- offloads->udp_ipv4_csum = 0;
- offloads->udp_ipv6_csum = 0;
- }
-
- request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
- RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
- if (!request)
- return (ENOMEM);
-
- set = &request->request_msg.msg.set_request;
- set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
- set->info_buffer_length = extlen;
- set->info_buffer_offset = sizeof(rndis_set_request);
- set->device_vc_handle = 0;
-
- offload_req = (rndis_offload_params *)((unsigned long)set +
- set->info_buffer_offset);
- *offload_req = *offloads;
- offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
- offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
- offload_req->header.size = extlen;
-
- ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
- if (ret != 0) {
- device_printf(dev, "hv send offload request failed, ret=%d!\n",
- ret);
- goto cleanup;
- }
-
- ret = sema_timedwait(&request->wait_sema, 5 * hz);
- if (ret != 0) {
- device_printf(dev, "hv send offload request timeout\n");
- goto cleanup;
- }
-
- set_complete = &request->response_msg.msg.set_complete;
- if (set_complete->status == RNDIS_STATUS_SUCCESS) {
- device_printf(dev, "hv send offload request succeeded\n");
- ret = 0;
- } else {
- if (set_complete->status == RNDIS_STATUS_NOT_SUPPORTED) {
- device_printf(dev, "HV Not support offload\n");
- ret = 0;
- } else {
- ret = set_complete->status;
- }
- }
-
-cleanup:
- hv_put_rndis_request(rndis_dev, request);
-
- return (ret);
-}
-
/*
* RNDIS filter receive indicate status
*/
@@ -628,77 +550,6 @@ hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
}
/*
- * RNDIS filter query device
- */
-static int
-hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
- uint32_t *result_size)
-{
- rndis_request *request;
- uint32_t in_result_size = *result_size;
- rndis_query_request *query;
- rndis_query_complete *query_complete;
- int ret = 0;
-
- *result_size = 0;
- request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
- RNDIS_MESSAGE_SIZE(rndis_query_request));
- if (request == NULL) {
- ret = -1;
- goto cleanup;
- }
-
- /* Set up the rndis query */
- query = &request->request_msg.msg.query_request;
- query->oid = oid;
- query->info_buffer_offset = sizeof(rndis_query_request);
- query->info_buffer_length = 0;
- query->device_vc_handle = 0;
-
- if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
- struct rndis_recv_scale_cap *cap;
-
- request->request_msg.msg_len +=
- sizeof(struct rndis_recv_scale_cap);
- query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
- cap = (struct rndis_recv_scale_cap *)((unsigned long)query +
- query->info_buffer_offset);
- cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
- cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
- cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
- }
-
- ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
- if (ret != 0) {
- /* Fixme: printf added */
- printf("RNDISFILTER request failed to Send!\n");
- goto cleanup;
- }
-
- sema_wait(&request->wait_sema);
-
- /* Copy the response back */
- query_complete = &request->response_msg.msg.query_complete;
-
- if (query_complete->info_buffer_length > in_result_size) {
- ret = EINVAL;
- goto cleanup;
- }
-
- memcpy(result, (void *)((unsigned long)query_complete +
- query_complete->info_buffer_offset),
- query_complete->info_buffer_length);
-
- *result_size = query_complete->info_buffer_length;
-
-cleanup:
- if (request != NULL)
- hv_put_rndis_request(device, request);
-
- return (ret);
-}
-
-/*
* RNDIS filter query device MAC address
*/
static int
@@ -712,12 +563,12 @@ hv_rf_query_device_mac(rndis_device *device)
error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
device->hw_mac_addr, &hwaddr_len);
if (error)
- return error;
+ return (error);
if (hwaddr_len != ETHER_ADDR_LEN) {
if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
- return EINVAL;
+ return (EINVAL);
}
- return 0;
+ return (0);
}
/*
@@ -726,13 +577,23 @@ hv_rf_query_device_mac(rndis_device *device)
static inline int
hv_rf_query_device_link_status(rndis_device *device)
{
- uint32_t size = sizeof(uint32_t);
+ struct hn_softc *sc = device->sc;
+ size_t size;
+ int error;
- return (hv_rf_query_device(device,
- RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
+ size = sizeof(uint32_t);
+ error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
+ &device->link_status, &size);
+ if (error)
+ return (error);
+ if (size != sizeof(uint32_t)) {
+ if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
+ return (EINVAL);
+ }
+ return (0);
}
-static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
+static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
@@ -740,172 +601,6 @@ static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
};
-/*
- * RNDIS set vRSS parameters
- */
-static int
-hv_rf_set_rss_param(rndis_device *device, int num_queue)
-{
- rndis_request *request;
- rndis_set_request *set;
- rndis_set_complete *set_complete;
- rndis_recv_scale_param *rssp;
- uint32_t extlen = sizeof(rndis_recv_scale_param) +
- (4 * ITAB_NUM) + HASH_KEYLEN;
- uint32_t *itab, status;
- uint8_t *keyp;
- int i, ret;
-
-
- request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
- RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
- if (request == NULL) {
- if (bootverbose)
- printf("Netvsc: No memory to set vRSS parameters.\n");
- ret = -1;
- goto cleanup;
- }
-
- set = &request->request_msg.msg.set_request;
- set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
- set->info_buffer_length = extlen;
- set->info_buffer_offset = sizeof(rndis_set_request);
- set->device_vc_handle = 0;
-
- /* Fill out the rssp parameter structure */
- rssp = (rndis_recv_scale_param *)(set + 1);
- rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
- rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
- rssp->hdr.size = sizeof(rndis_recv_scale_param);
- rssp->flag = 0;
- rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
- RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
- rssp->indirect_tabsize = 4 * ITAB_NUM;
- rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
- rssp->hashkey_size = HASH_KEYLEN;
- rssp->hashkey_offset = rssp->indirect_taboffset +
- rssp->indirect_tabsize;
-
- /* Set indirection table entries */
- itab = (uint32_t *)(rssp + 1);
- for (i = 0; i < ITAB_NUM; i++)
- itab[i] = i % num_queue;
-
- /* Set hash key values */
- keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
- for (i = 0; i < HASH_KEYLEN; i++)
- keyp[i] = netvsc_hash_key[i];
-
- ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
- if (ret != 0) {
- goto cleanup;
- }
-
- /*
- * Wait for the response from the host. Another thread will signal
- * us when the response has arrived. In the failure case,
- * sema_timedwait() returns a non-zero status after waiting 5 seconds.
- */
- ret = sema_timedwait(&request->wait_sema, 5 * hz);
- if (ret == 0) {
- /* Response received, check status */
- set_complete = &request->response_msg.msg.set_complete;
- status = set_complete->status;
- if (status != RNDIS_STATUS_SUCCESS) {
- /* Bad response status, return error */
- if (bootverbose)
- printf("Netvsc: Failed to set vRSS "
- "parameters.\n");
- ret = -2;
- } else {
- if (bootverbose)
- printf("Netvsc: Successfully set vRSS "
- "parameters.\n");
- }
- } else {
- /*
- * We cannot deallocate the request since we may still
- * receive a send completion for it.
- */
- printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
- request->request_msg.msg.init_request.request_id, ret);
- goto exit;
- }
-
-cleanup:
- if (request != NULL) {
- hv_put_rndis_request(device, request);
- }
-exit:
- return (ret);
-}
-
-/*
- * RNDIS filter set packet filter
- * Sends an rndis request with the new filter, then waits for a response
- * from the host.
- * Returns zero on success, non-zero on failure.
- */
-static int
-hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
-{
- rndis_request *request;
- rndis_set_request *set;
- rndis_set_complete *set_complete;
- uint32_t status;
- int ret;
-
- request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
- RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
- if (request == NULL) {
- ret = -1;
- goto cleanup;
- }
-
- /* Set up the rndis set */
- set = &request->request_msg.msg.set_request;
- set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
- set->info_buffer_length = sizeof(uint32_t);
- set->info_buffer_offset = sizeof(rndis_set_request);
-
- memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
- &new_filter, sizeof(uint32_t));
-
- ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
- if (ret != 0) {
- goto cleanup;
- }
-
- /*
- * Wait for the response from the host. Another thread will signal
- * us when the response has arrived. In the failure case,
- * sema_timedwait() returns a non-zero status after waiting 5 seconds.
- */
- ret = sema_timedwait(&request->wait_sema, 5 * hz);
- if (ret == 0) {
- /* Response received, check status */
- set_complete = &request->response_msg.msg.set_complete;
- status = set_complete->status;
- if (status != RNDIS_STATUS_SUCCESS) {
- /* Bad response status, return error */
- ret = -2;
- }
- } else {
- /*
- * We cannot deallocate the request since we may still
- * receive a send completion for it.
- */
- goto exit;
- }
-
-cleanup:
- if (request != NULL) {
- hv_put_rndis_request(device, request);
- }
-exit:
- return (ret);
-}
-
static const void *
hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
size_t reqlen, size_t *comp_len0, uint32_t comp_type)
@@ -1083,6 +778,51 @@ done:
}
static int
+hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
+{
+ struct ndis_rss_caps in, caps;
+ size_t caps_len;
+ int error;
+
+ /*
+ * Only NDIS 6.30+ is supported.
+ */
+ KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
+ ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
+ *rxr_cnt = 0;
+
+ memset(&in, 0, sizeof(in));
+ in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
+ in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
+ in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
+
+ caps_len = NDIS_RSS_CAPS_SIZE;
+ error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
+ &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
+ if (error)
+ return (error);
+ if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
+ if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
+ caps_len);
+ return (EINVAL);
+ }
+
+ if (caps.ndis_nrxr == 0) {
+ if_printf(sc->hn_ifp, "0 RX rings!?\n");
+ return (EINVAL);
+ }
+ *rxr_cnt = caps.ndis_nrxr;
+
+ if (caps_len == NDIS_RSS_CAPS_SIZE) {
+ if (bootverbose) {
+ if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
+ caps.ndis_nind);
+ }
+ }
+ return (0);
+}
+
+static int
hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
{
struct rndis_set_req *req;
@@ -1172,6 +912,72 @@ hn_rndis_conf_offload(struct hn_softc *sc)
return (error);
}
+static int
+hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
+{
+ struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
+ struct ndis_rss_params *prm = &rss->rss_params;
+ int i, error;
+
+ /*
+ * Only NDIS 6.30+ is supported.
+ */
+ KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
+ ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
+
+ memset(rss, 0, sizeof(*rss));
+ prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
+ prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
+ prm->ndis_hdr.ndis_size = sizeof(*rss);
+ prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
+ NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
+ NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
+ /* TODO: Take ndis_rss_caps.ndis_nind into account */
+ prm->ndis_indsize = sizeof(rss->rss_ind);
+ prm->ndis_indoffset =
+ __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
+ prm->ndis_keysize = sizeof(rss->rss_key);
+ prm->ndis_keyoffset =
+ __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
+
+ /* Setup RSS key */
+ memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
+
+ /* Setup RSS indirect table */
+ /* TODO: Take ndis_rss_caps.ndis_nind into account */
+ for (i = 0; i < NDIS_HASH_INDCNT; ++i)
+ rss->rss_ind[i] = i % nchan;
+
+ error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
+ rss, sizeof(*rss));
+ if (error) {
+ if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
+ } else {
+ if (bootverbose)
+ if_printf(sc->hn_ifp, "RSS config done\n");
+ }
+ return (error);
+}
+
+static int
+hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
+{
+ int error;
+
+ error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
+ &filter, sizeof(filter));
+ if (error) {
+ if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
+ filter, error);
+ } else {
+ if (bootverbose) {
+ if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
+ filter);
+ }
+ }
+ return (error);
+}
+
/*
* RNDIS filter init device
*/
@@ -1280,55 +1086,6 @@ hv_rf_halt_device(rndis_device *device)
}
/*
- * RNDIS filter open device
- */
-static int
-hv_rf_open_device(rndis_device *device)
-{
- int ret;
-
- if (device->state != RNDIS_DEV_INITIALIZED) {
- return (0);
- }
-
- if (hv_promisc_mode != 1) {
- ret = hv_rf_set_packet_filter(device,
- NDIS_PACKET_TYPE_BROADCAST |
- NDIS_PACKET_TYPE_ALL_MULTICAST |
- NDIS_PACKET_TYPE_DIRECTED);
- } else {
- ret = hv_rf_set_packet_filter(device,
- NDIS_PACKET_TYPE_PROMISCUOUS);
- }
-
- if (ret == 0) {
- device->state = RNDIS_DEV_DATAINITIALIZED;
- }
-
- return (ret);
-}
-
-/*
- * RNDIS filter close device
- */
-static int
-hv_rf_close_device(rndis_device *device)
-{
- int ret;
-
- if (device->state != RNDIS_DEV_DATAINITIALIZED) {
- return (0);
- }
-
- ret = hv_rf_set_packet_filter(device, 0);
- if (ret == 0) {
- device->state = RNDIS_DEV_INITIALIZED;
- }
-
- return (ret);
-}
-
-/*
* RNDIS filter on device add
*/
int
@@ -1337,8 +1094,6 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
{
int ret;
rndis_device *rndis_dev;
- struct rndis_recv_scale_cap rsscaps;
- uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
device_t dev = sc->hn_dev;
struct hn_nvs_subch_req *req;
@@ -1347,6 +1102,7 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
struct vmbus_xact *xact = NULL;
uint32_t status, nsubch;
int nchan = *nchan0;
+ int rxr_cnt;
rndis_dev = hv_get_rndis_device();
if (rndis_dev == NULL) {
@@ -1395,22 +1151,29 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
dev_info->link_state = rndis_dev->link_status;
- if (sc->hn_nvs_ver < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
+ if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
+ /*
+ * Either RSS is not supported, or multiple RX/TX rings
+ * are not requested.
+ */
+ *nchan0 = 1;
return (0);
+ }
- memset(&rsscaps, 0, rsscaps_size);
- ret = hv_rf_query_device(rndis_dev,
- RNDIS_OID_GEN_RSS_CAPABILITIES,
- &rsscaps, &rsscaps_size);
- if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
- device_printf(dev, "hv_rf_query_device failed or "
- "rsscaps.num_recv_que < 2 \n");
- goto out;
+ /*
+ * Get RSS capabilities, e.g. # of RX rings, and # of indirect
+ * table entries.
+ */
+ ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
+ if (ret) {
+ /* No RSS; this is benign. */
+ *nchan0 = 1;
+ return (0);
}
- device_printf(dev, "channel, offered %u, requested %d\n",
- rsscaps.num_recv_que, nchan);
- if (nchan > rsscaps.num_recv_que)
- nchan = rsscaps.num_recv_que;
+ if (nchan > rxr_cnt)
+ nchan = rxr_cnt;
+ if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
+ rxr_cnt, nchan);
if (nchan == 1) {
device_printf(dev, "only 1 channel is supported, no vRSS\n");
@@ -1467,8 +1230,11 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
}
nchan = nsubch + 1;
- ret = hv_rf_set_rss_param(rndis_dev, nchan);
- *nchan0 = nchan;
+ ret = hn_rndis_conf_rss(sc, nchan);
+ if (ret != 0)
+ *nchan0 = 1;
+ else
+ *nchan0 = nchan;
out:
if (xact != NULL)
vmbus_xact_put(xact);
@@ -1502,8 +1268,17 @@ hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
int
hv_rf_on_open(struct hn_softc *sc)
{
+ uint32_t filter;
- return (hv_rf_open_device(sc->rndis_dev));
+ /* XXX */
+ if (hv_promisc_mode != 1) {
+ filter = NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_DIRECTED;
+ } else {
+ filter = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+ return (hn_rndis_set_rxfilter(sc, filter));
}
/*
@@ -1513,7 +1288,7 @@ int
hv_rf_on_close(struct hn_softc *sc)
{
- return (hv_rf_close_device(sc->rndis_dev));
+ return (hn_rndis_set_rxfilter(sc, 0));
}
static void
diff --git a/sys/dev/hyperv/netvsc/ndis.h b/sys/dev/hyperv/netvsc/ndis.h
index 10e0af2..b5f9aa7 100644
--- a/sys/dev/hyperv/netvsc/ndis.h
+++ b/sys/dev/hyperv/netvsc/ndis.h
@@ -29,93 +29,178 @@
#ifndef _NET_NDIS_H_
#define _NET_NDIS_H_
-#define NDIS_MEDIA_STATE_CONNECTED 0
-#define NDIS_MEDIA_STATE_DISCONNECTED 1
+#define NDIS_MEDIA_STATE_CONNECTED 0
+#define NDIS_MEDIA_STATE_DISCONNECTED 1
-#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C
+#define NDIS_OFFLOAD_SET_NOCHG 0
+#define NDIS_OFFLOAD_SET_ON 1
+#define NDIS_OFFLOAD_SET_OFF 2
-#define NDIS_OBJTYPE_DEFAULT 0x80
+/* a.k.a GRE MAC */
+#define NDIS_ENCAP_TYPE_NVGRE 0x00000001
-/* common_set */
-#define NDIS_OFFLOAD_SET_NOCHG 0
-#define NDIS_OFFLOAD_SET_ON 1
-#define NDIS_OFFLOAD_SET_OFF 2
+#define NDIS_HASH_FUNCTION_MASK 0x000000FF /* see hash function */
+#define NDIS_HASH_TYPE_MASK 0x00FFFF00 /* see hash type */
-/* a.k.a GRE MAC */
-#define NDIS_ENCAP_TYPE_NVGRE 0x00000001
+/* hash function */
+#define NDIS_HASH_FUNCTION_TOEPLITZ 0x00000001
+
+/* hash type */
+#define NDIS_HASH_IPV4 0x00000100
+#define NDIS_HASH_TCP_IPV4 0x00000200
+#define NDIS_HASH_IPV6 0x00000400
+#define NDIS_HASH_IPV6_EX 0x00000800
+#define NDIS_HASH_TCP_IPV6 0x00001000
+#define NDIS_HASH_TCP_IPV6_EX 0x00002000
+
+#define NDIS_HASH_KEYSIZE_TOEPLITZ 40
+#define NDIS_HASH_INDCNT 128
+
+#define NDIS_OBJTYPE_DEFAULT 0x80
+#define NDIS_OBJTYPE_RSS_CAPS 0x88
+#define NDIS_OBJTYPE_RSS_PARAMS 0x89
struct ndis_object_hdr {
- uint8_t ndis_type; /* NDIS_OBJTYPE_ */
- uint8_t ndis_rev; /* type specific */
- uint16_t ndis_size; /* incl. this hdr */
+ uint8_t ndis_type; /* NDIS_OBJTYPE_ */
+ uint8_t ndis_rev; /* type specific */
+ uint16_t ndis_size; /* incl. this hdr */
};
-/* OID_TCP_OFFLOAD_PARAMETERS */
+/*
+ * OID_TCP_OFFLOAD_PARAMETERS
+ * ndis_type: NDIS_OBJTYPE_DEFAULT
+ */
struct ndis_offload_params {
struct ndis_object_hdr ndis_hdr;
- uint8_t ndis_ip4csum; /* param_set */
- uint8_t ndis_tcp4csum; /* param_set */
- uint8_t ndis_udp4csum; /* param_set */
- uint8_t ndis_tcp6csum; /* param_set */
- uint8_t ndis_udp6csum; /* param_set */
- uint8_t ndis_lsov1; /* lsov1_set */
- uint8_t ndis_ipsecv1; /* ipsecv1_set */
- uint8_t ndis_lsov2_ip4; /* lsov2_set */
- uint8_t ndis_lsov2_ip6; /* lsov2_set */
- uint8_t ndis_tcp4conn; /* PARAM_NOCHG */
- uint8_t ndis_tcp6conn; /* PARAM_NOCHG */
- uint32_t ndis_flags; /* 0 */
+ uint8_t ndis_ip4csum; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_tcp4csum; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_udp4csum; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_tcp6csum; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_udp6csum; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_lsov1; /* NDIS_OFFLOAD_PARAM_ */
+ uint8_t ndis_ipsecv1; /* NDIS_OFFLOAD_IPSECV1_ */
+ uint8_t ndis_lsov2_ip4; /* NDIS_OFFLOAD_LSOV2_ */
+ uint8_t ndis_lsov2_ip6; /* NDIS_OFFLOAD_LSOV2_ */
+ uint8_t ndis_tcp4conn; /* 0 */
+ uint8_t ndis_tcp6conn; /* 0 */
+ uint32_t ndis_flags; /* 0 */
/* NDIS >= 6.1 */
- uint8_t ndis_ipsecv2; /* ipsecv2_set */
- uint8_t ndis_ipsecv2_ip4; /* ipsecv2_set */
+ uint8_t ndis_ipsecv2; /* NDIS_OFFLOAD_IPSECV2_ */
+ uint8_t ndis_ipsecv2_ip4;/* NDIS_OFFLOAD_IPSECV2_ */
/* NDIS >= 6.30 */
- uint8_t ndis_rsc_ip4; /* rsc_set */
- uint8_t ndis_rsc_ip6; /* rsc_set */
- uint8_t ndis_encap; /* common_set */
- uint8_t ndis_encap_types; /* NDIS_ENCAP_TYPE_ */
+ uint8_t ndis_rsc_ip4; /* NDIS_OFFLOAD_RSC_ */
+ uint8_t ndis_rsc_ip6; /* NDIS_OFFLOAD_RSC_ */
+ uint8_t ndis_encap; /* NDIS_OFFLOAD_SET_ */
+ uint8_t ndis_encap_types;/* NDIS_ENCAP_TYPE_ */
};
-#define NDIS_OFFLOAD_PARAMS_SIZE sizeof(struct ndis_offload_params)
-#define NDIS_OFFLOAD_PARAMS_SIZE_6_1 \
+#define NDIS_OFFLOAD_PARAMS_SIZE sizeof(struct ndis_offload_params)
+#define NDIS_OFFLOAD_PARAMS_SIZE_6_1 \
__offsetof(struct ndis_offload_params, ndis_rsc_ip4)
-#define NDIS_OFFLOAD_PARAMS_REV_2 2 /* NDIS 6.1 */
-#define NDIS_OFFLOAD_PARAMS_REV_3 3 /* NDIS 6.30 */
+#define NDIS_OFFLOAD_PARAMS_REV_2 2 /* NDIS 6.1 */
+#define NDIS_OFFLOAD_PARAMS_REV_3 3 /* NDIS 6.30 */
-/* param_set */
-#define NDIS_OFFLOAD_PARAM_NOCHG 0 /* common to all sets */
-#define NDIS_OFFLOAD_PARAM_OFF 1
-#define NDIS_OFFLOAD_PARAM_TX 2
-#define NDIS_OFFLOAD_PARAM_RX 3
-#define NDIS_OFFLOAD_PARAM_TXRX 4
+#define NDIS_OFFLOAD_PARAM_NOCHG 0 /* common */
+#define NDIS_OFFLOAD_PARAM_OFF 1
+#define NDIS_OFFLOAD_PARAM_TX 2
+#define NDIS_OFFLOAD_PARAM_RX 3
+#define NDIS_OFFLOAD_PARAM_TXRX 4
-/* lsov1_set */
/* NDIS_OFFLOAD_PARAM_NOCHG */
-#define NDIS_OFFLOAD_LSOV1_OFF 1
-#define NDIS_OFFLOAD_LSOV1_ON 2
+#define NDIS_OFFLOAD_LSOV1_OFF 1
+#define NDIS_OFFLOAD_LSOV1_ON 2
-/* ipsecv1_set */
/* NDIS_OFFLOAD_PARAM_NOCHG */
-#define NDIS_OFFLOAD_IPSECV1_OFF 1
-#define NDIS_OFFLOAD_IPSECV1_AH 2
-#define NDIS_OFFLOAD_IPSECV1_ESP 3
-#define NDIS_OFFLOAD_IPSECV1_AH_ESP 4
+#define NDIS_OFFLOAD_IPSECV1_OFF 1
+#define NDIS_OFFLOAD_IPSECV1_AH 2
+#define NDIS_OFFLOAD_IPSECV1_ESP 3
+#define NDIS_OFFLOAD_IPSECV1_AH_ESP 4
-/* lsov2_set */
/* NDIS_OFFLOAD_PARAM_NOCHG */
-#define NDIS_OFFLOAD_LSOV2_OFF 1
-#define NDIS_OFFLOAD_LSOV2_ON 2
+#define NDIS_OFFLOAD_LSOV2_OFF 1
+#define NDIS_OFFLOAD_LSOV2_ON 2
-/* ipsecv2_set */
/* NDIS_OFFLOAD_PARAM_NOCHG */
-#define NDIS_OFFLOAD_IPSECV2_OFF 1
-#define NDIS_OFFLOAD_IPSECV2_AH 2
-#define NDIS_OFFLOAD_IPSECV2_ESP 3
-#define NDIS_OFFLOAD_IPSECV2_AH_ESP 4
+#define NDIS_OFFLOAD_IPSECV2_OFF 1
+#define NDIS_OFFLOAD_IPSECV2_AH 2
+#define NDIS_OFFLOAD_IPSECV2_ESP 3
+#define NDIS_OFFLOAD_IPSECV2_AH_ESP 4
-/* rsc_set */
/* NDIS_OFFLOAD_PARAM_NOCHG */
-#define NDIS_OFFLOAD_RSC_OFF 1
-#define NDIS_OFFLOAD_RSC_ON 2
+#define NDIS_OFFLOAD_RSC_OFF 1
+#define NDIS_OFFLOAD_RSC_ON 2
+
+/*
+ * OID_GEN_RECEIVE_SCALE_CAPABILITIES
+ * ndis_type: NDIS_OBJTYPE_RSS_CAPS
+ */
+struct ndis_rss_caps {
+ struct ndis_object_hdr ndis_hdr;
+ uint32_t ndis_flags; /* NDIS_RSS_CAP_ */
+ uint32_t ndis_nmsi; /* # of MSIs */
+ uint32_t ndis_nrxr; /* # of RX rings */
+ /* NDIS >= 6.30 */
+ uint16_t ndis_nind; /* # of indtbl ent. */
+ uint16_t ndis_pad;
+};
+
+#define NDIS_RSS_CAPS_SIZE \
+ __offsetof(struct ndis_rss_caps, ndis_pad)
+#define NDIS_RSS_CAPS_SIZE_6_0 \
+ __offsetof(struct ndis_rss_caps, ndis_nind)
+
+#define NDIS_RSS_CAPS_REV_1 1 /* NDIS 6.{0,1,20} */
+#define NDIS_RSS_CAPS_REV_2 2 /* NDIS 6.30 */
+
+#define NDIS_RSS_CAP_MSI 0x01000000
+#define NDIS_RSS_CAP_CLASSIFY_ISR 0x02000000
+#define NDIS_RSS_CAP_CLASSIFY_DPC 0x04000000
+#define NDIS_RSS_CAP_MSIX 0x08000000
+#define NDIS_RSS_CAP_IPV4 0x00000100
+#define NDIS_RSS_CAP_IPV6 0x00000200
+#define NDIS_RSS_CAP_IPV6_EX 0x00000400
+#define NDIS_RSS_CAP_HASH_TOEPLITZ 0x00000001
+
+/*
+ * OID_GEN_RECEIVE_SCALE_PARAMETERS
+ * ndis_type: NDIS_OBJTYPE_RSS_PARAMS
+ */
+struct ndis_rss_params {
+ struct ndis_object_hdr ndis_hdr;
+ uint16_t ndis_flags; /* NDIS_RSS_FLAG_ */
+ uint16_t ndis_bcpu; /* base cpu 0 */
+ uint32_t ndis_hash; /* NDIS_HASH_ */
+ uint16_t ndis_indsize; /* indirect table */
+ uint32_t ndis_indoffset;
+ uint16_t ndis_keysize; /* hash key */
+ uint32_t ndis_keyoffset;
+ /* NDIS >= 6.20 */
+ uint32_t ndis_cpumaskoffset;
+ uint32_t ndis_cpumaskcnt;
+ uint32_t ndis_cpumaskentsz;
+};
+
+#define NDIS_RSS_PARAMS_SIZE sizeof(struct ndis_rss_params)
+#define NDIS_RSS_PARAMS_SIZE_6_0 \
+ __offsetof(struct ndis_rss_params, ndis_cpumaskoffset)
+
+#define NDIS_RSS_PARAMS_REV_1 1 /* NDIS 6.0 */
+#define NDIS_RSS_PARAMS_REV_2 2 /* NDIS 6.20 */
+
+#define NDIS_RSS_FLAG_BCPU_UNCHG 0x0001
+#define NDIS_RSS_FLAG_HASH_UNCHG 0x0002
+#define NDIS_RSS_FLAG_IND_UNCHG 0x0004
+#define NDIS_RSS_FLAG_KEY_UNCHG 0x0008
+#define NDIS_RSS_FLAG_DISABLE 0x0010
+
+/* non-standard convenient struct */
+struct ndis_rssprm_toeplitz {
+ struct ndis_rss_params rss_params;
+ /* Toeplitz hash key */
+ uint8_t rss_key[NDIS_HASH_KEYSIZE_TOEPLITZ];
+ /* Indirect table */
+ uint32_t rss_ind[NDIS_HASH_INDCNT];
+};
#endif /* !_NET_NDIS_H_ */
OpenPOWER on IntegriCloud