Author: sephe
Date: Thu Aug 25 05:00:41 2016
New Revision: 304785
URL: https://svnweb.freebsd.org/changeset/base/304785

Log:
  hyperv/hn: Use vmbus xact for RNDIS initialize.
  
  MFC after:    1 week
  Sponsored by: Microsoft
  Differential Revision:        https://reviews.freebsd.org/D7624

Modified:
  head/sys/dev/hyperv/netvsc/hv_net_vsc.c
  head/sys/dev/hyperv/netvsc/hv_net_vsc.h
  head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  head/sys/dev/hyperv/netvsc/if_hnvar.h
  head/sys/net/rndis.h

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.c     Thu Aug 25 04:52:50 2016        
(r304784)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.c     Thu Aug 25 05:00:41 2016        
(r304785)
@@ -77,7 +77,7 @@ static void hn_nvs_sent_none(struct hn_s
 static void hn_nvs_sent_xact(struct hn_send_ctx *, struct hn_softc *sc,
     struct vmbus_channel *, const void *, int);
 
-static struct hn_send_ctx      hn_send_ctx_none =
+struct hn_send_ctx     hn_send_ctx_none =
     HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
 
 uint32_t

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Thu Aug 25 04:52:50 2016        
(r304784)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Thu Aug 25 05:00:41 2016        
(r304785)
@@ -239,6 +239,11 @@ typedef struct {
        uint8_t         link_state;
 } netvsc_device_info;
 
+#define HN_XACT_REQ_PGCNT              2
+#define HN_XACT_RESP_PGCNT             2
+#define HN_XACT_REQ_SIZE               (HN_XACT_REQ_PGCNT * PAGE_SIZE)
+#define HN_XACT_RESP_SIZE              (HN_XACT_RESP_PGCNT * PAGE_SIZE)
+
 #ifndef HN_USE_TXDESC_BUFRING
 struct hn_txdesc;
 SLIST_HEAD(hn_txdesc_list, hn_txdesc);
@@ -375,6 +380,8 @@ typedef struct hn_softc {
 
        uint32_t                hn_chim_gpadl;
        struct hyperv_dma       hn_chim_dma;
+
+       uint32_t                hn_rndis_rid;
 } hn_softc_t;
 
 #define HN_FLAG_RXBUF_CONNECTED                0x0001

Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Thu Aug 25 04:52:50 
2016        (r304784)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Thu Aug 25 05:00:41 
2016        (r304785)
@@ -125,9 +125,6 @@ __FBSDID("$FreeBSD$");
 /* Short for Hyper-V network interface */
 #define NETVSC_DEVNAME    "hn"
 
-#define HN_XACT_REQ_SIZE               (2 * PAGE_SIZE)
-#define HN_XACT_RESP_SIZE              (2 * PAGE_SIZE)
-
 /*
  * It looks like offset 0 of buf is reserved to hold the softc pointer.
  * The sc pointer evidently not needed, and is not presently populated.

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Thu Aug 25 04:52:50 
2016        (r304784)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Thu Aug 25 05:00:41 
2016        (r304785)
@@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
 #define HN_RNDIS_RID_COMPAT_MASK       0xffff
 #define HN_RNDIS_RID_COMPAT_MAX                HN_RNDIS_RID_COMPAT_MASK
 
+#define HN_RNDIS_XFER_SIZE             2048
+
 /*
  * Forward declarations
  */
@@ -95,6 +97,20 @@ static void hn_rndis_sent_cb(struct hn_s
     struct hn_softc *sc, struct vmbus_channel *chan,
     const void *data, int dlen);
 
+static __inline uint32_t
+hn_rndis_rid(struct hn_softc *sc)
+{
+       uint32_t rid;
+
+again:
+       rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
+       if (rid == 0)
+               goto again;
+
+       /* Use upper 16 bits for non-compat RNDIS messages. */
+       return ((rid & 0xffff) << 16);
+}
+
 /*
  * Set the Per-Packet-Info with the specified type
  */
@@ -576,6 +592,8 @@ hv_rf_on_receive(struct hn_softc *sc, st
                if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
                        /* Transition time compat code */
                        hv_rf_receive_response(rndis_dev, rndis_hdr);
+               } else {
+                       vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
                }
                break;
 
@@ -872,62 +890,139 @@ exit:
        return (ret);
 }
 
-/*
- * RNDIS filter init device
- */
-static int
-hv_rf_init_device(rndis_device *device)
+static const void *
+hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t 
rid,
+    size_t reqlen, size_t min_complen, uint32_t comp_type)
 {
-       rndis_request *request;
-       rndis_initialize_request *init;
-       rndis_initialize_complete *init_complete;
-       uint32_t status;
-       int ret;
+       struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
+       const struct rndis_comp_hdr *comp;
+       bus_addr_t paddr;
+       size_t comp_len;
+       int gpa_cnt, error;
+
+       KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
+       KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
+           ("invalid request length %zu", reqlen));
+       KASSERT(min_complen >= sizeof(*comp),
+           ("invalid minimum complete len %zu", min_complen));
 
-       request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
-           RNDIS_MESSAGE_SIZE(rndis_initialize_request));
-       if (!request) {
-               ret = -1;
-               goto cleanup;
+       /*
+        * Setup the SG list.
+        */
+       paddr = vmbus_xact_req_paddr(xact);
+       KASSERT((paddr & PAGE_MASK) == 0,
+           ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
+       for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
+               int len = PAGE_SIZE;
+
+               if (reqlen == 0)
+                       break;
+               if (reqlen < len)
+                       len = reqlen;
+
+               gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
+               gpa[gpa_cnt].gpa_len = len;
+               gpa[gpa_cnt].gpa_ofs = 0;
+
+               reqlen -= len;
        }
+       KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
 
-       /* Set up the rndis set */
-       init = &request->request_msg.msg.init_request;
-       init->major_version = RNDIS_VERSION_MAJOR;
-       init->minor_version = RNDIS_VERSION_MINOR;
        /*
-        * Per the RNDIS document, this should be set to the max MTU
-        * plus the header size.  However, 2048 works fine, so leaving
-        * it as is.
+        * Send this RNDIS control message and wait for its completion
+        * message.
         */
-       init->max_xfer_size = 2048;
-       
-       device->state = RNDIS_DEV_INITIALIZING;
+       vmbus_xact_activate(xact);
+       error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
+           &hn_send_ctx_none, gpa, gpa_cnt);
+       if (error) {
+               vmbus_xact_deactivate(xact);
+               if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
+               return (NULL);
+       }
+       comp = vmbus_xact_wait(xact, &comp_len);
 
-       ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
-       if (ret != 0) {
-               device->state = RNDIS_DEV_UNINITIALIZED;
-               goto cleanup;
+       /*
+        * Check this RNDIS complete message.
+        */
+       if (comp_len < min_complen) {
+               if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n", comp_len);
+               return (NULL);
+       }
+       if (comp->rm_len < min_complen) {
+               if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
+                   comp->rm_len);
+               return (NULL);
+       }
+       if (comp->rm_type != comp_type) {
+               if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
+                   "expect 0x%08x\n", comp->rm_type, comp_type);
+               return (NULL);
+       }
+       if (comp->rm_rid != rid) {
+               if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
+                   "expect %u\n", comp->rm_rid, rid);
+               return (NULL);
        }
+       /* All pass! */
+       return (comp);
+}
 
-       sema_wait(&request->wait_sema);
+/*
+ * RNDIS filter init device
+ */
+static int
+hv_rf_init_device(rndis_device *device)
+{
+       struct hn_softc *sc = device->sc;
+       struct rndis_init_req *req;
+       const struct rndis_init_comp *comp;
+       struct vmbus_xact *xact;
+       uint32_t rid;
+       int error;
 
-       init_complete = &request->response_msg.msg.init_complete;
-       status = init_complete->status;
-       if (status == RNDIS_STATUS_SUCCESS) {
-               device->state = RNDIS_DEV_INITIALIZED;
-               ret = 0;
-       } else {
-               device->state = RNDIS_DEV_UNINITIALIZED; 
-               ret = -1;
-       }
+       /* XXX */
+       device->state = RNDIS_DEV_INITIALIZED;
 
-cleanup:
-       if (request) {
-               hv_put_rndis_request(device, request);
+       xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
+       if (xact == NULL) {
+               if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
+               return (ENXIO);
+       }
+       rid = hn_rndis_rid(sc);
+       req = vmbus_xact_req_data(xact);
+       req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
+       req->rm_len = sizeof(*req);
+       req->rm_rid = rid;
+       req->rm_ver_major = RNDIS_VERSION_MAJOR;
+       req->rm_ver_minor = RNDIS_VERSION_MINOR;
+       req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
+
+       comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req),
+           RNDIS_INIT_COMP_SIZE_MIN, REMOTE_NDIS_INITIALIZE_CMPLT);
+       if (comp == NULL) {
+               if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
+               error = EIO;
+               goto done;
+       }
+
+       if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
+               if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
+                   comp->rm_status);
+               error = EIO;
+               goto done;
+       }
+       if (bootverbose) {
+               if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
+                   comp->rm_ver_major, comp->rm_ver_minor,
+                   comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
        }
+       error = 0;
 
-       return (ret);
+done:
+       if (xact != NULL)
+               vmbus_xact_put(xact);
+       return (error);
 }
 
 #define HALT_COMPLETION_WAIT_COUNT      25

Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h       Thu Aug 25 04:52:50 2016        
(r304784)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h       Thu Aug 25 05:00:41 2016        
(r304785)
@@ -115,4 +115,6 @@ const void  *hn_nvs_xact_execute(struct h
 uint32_t       hn_chim_alloc(struct hn_softc *sc);
 void           hn_chim_free(struct hn_softc *sc, uint32_t chim_idx);
 
+extern struct hn_send_ctx      hn_send_ctx_none;
+
 #endif /* !_IF_HNVAR_H_ */

Modified: head/sys/net/rndis.h
==============================================================================
--- head/sys/net/rndis.h        Thu Aug 25 04:52:50 2016        (r304784)
+++ head/sys/net/rndis.h        Thu Aug 25 05:00:41 2016        (r304785)
@@ -146,6 +146,9 @@ struct rndis_init_comp {
        uint32_t rm_aflistsz;
 };
 
+#define        RNDIS_INIT_COMP_SIZE_MIN        \
+       __offsetof(struct rndis_init_comp, rm_aflistsz)
+
 /* Halt the device.  No response sent. */
 #define        REMOTE_NDIS_HALT_MSG            0x00000003
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to