Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Aug 2016 05:43:28 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r304447 - head/sys/dev/hyperv/netvsc
Message-ID:  <201608190543.u7J5hSJi055331@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Aug 19 05:43:28 2016
New Revision: 304447
URL: https://svnweb.freebsd.org/changeset/base/304447

Log:
  hyperv/hn: Move RXBUF to hn_softc
  
  And don't recreate RXBUF for each primary channel open, it is now
  created in device_attach DEVMETHOD and destroyed in device_detach
  DEVMETHOD.
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D7556

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

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Aug 19 05:30:39 2016	(r304446)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.c	Fri Aug 19 05:43:28 2016	(r304447)
@@ -59,9 +59,9 @@ MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper
 static void hv_nv_on_channel_callback(struct vmbus_channel *chan,
     void *xrxr);
 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 *, int);
 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(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,
     struct vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt);
@@ -146,29 +146,18 @@ hv_nv_get_next_send_section(netvsc_dev *
  *     Hyper-V extensible switch and the synthetic data path.
  */
 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, int rxbuf_size)
 {
 	struct vmbus_xact *xact;
 	struct hn_nvs_rxbuf_conn *conn;
 	const struct hn_nvs_rxbuf_connresp *resp;
 	size_t resp_len;
 	struct hn_send_ctx sndc;
-	netvsc_dev *net_dev;
 	uint32_t status;
 	int error;
 
-	net_dev = hv_nv_get_outbound_net_device(sc);
-	if (!net_dev) {
-		return (ENODEV);
-	}
-
-	net_dev->rx_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
-	    PAGE_SIZE, 0, net_dev->rx_buf_size, &net_dev->rxbuf_dma,
-	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
-	if (net_dev->rx_buf == NULL) {
-		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
-		return (ENOMEM);
-	}
+	KASSERT(rxbuf_size <= NETVSC_RECEIVE_BUFFER_SIZE,
+	    ("invalid rxbuf size %d", rxbuf_size));
 
 	/*
 	 * Connect the RXBUF GPADL to the primary channel.
@@ -178,8 +167,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 	 * just share this RXBUF.
 	 */
 	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
-	    net_dev->rxbuf_dma.hv_paddr, net_dev->rx_buf_size,
-	    &net_dev->rx_buf_gpadl_handle);
+	    sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
 	if (error) {
 		if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
 		    error);
@@ -199,7 +187,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 
 	conn = vmbus_xact_req_data(xact);
 	conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
-	conn->nvs_gpadl = net_dev->rx_buf_gpadl_handle;
+	conn->nvs_gpadl = sc->hn_rxbuf_gpadl;
 	conn->nvs_sig = HN_NVS_RXBUF_SIG;
 
 	hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
@@ -239,12 +227,12 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 		error = EIO;
 		goto cleanup;
 	}
-	net_dev->rx_section_count = 1;
+	sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED;
 
 	return (0);
 
 cleanup:
-	hv_nv_destroy_rx_buffer(net_dev);
+	hv_nv_destroy_rx_buffer(sc);
 	return (error);
 }
 
@@ -376,11 +364,11 @@ cleanup:
  * Net VSC destroy receive buffer
  */
 static int
-hv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
+hv_nv_destroy_rx_buffer(struct hn_softc *sc)
 {
 	int ret = 0;
 
-	if (net_dev->rx_section_count) {
+	if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
 		struct hn_nvs_rxbuf_disconn disconn;
 
 		/*
@@ -391,37 +379,30 @@ hv_nv_destroy_rx_buffer(netvsc_dev *net_
 		disconn.nvs_sig = HN_NVS_RXBUF_SIG;
 
 		/* NOTE: No response. */
-		ret = hn_nvs_send(net_dev->sc->hn_prichan,
+		ret = hn_nvs_send(sc->hn_prichan,
 		    VMBUS_CHANPKT_FLAG_NONE, &disconn, sizeof(disconn),
 		    &hn_send_ctx_none);
 		if (ret != 0) {
-			if_printf(net_dev->sc->hn_ifp,
+			if_printf(sc->hn_ifp,
 			    "send rxbuf disconn failed: %d\n", ret);
 			return (ret);
 		}
-		net_dev->rx_section_count = 0;
+		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
 	}
 		
-	/* Tear down the gpadl on the vsp end */
-	if (net_dev->rx_buf_gpadl_handle) {
-		ret = vmbus_chan_gpadl_disconnect(net_dev->sc->hn_prichan,
-		    net_dev->rx_buf_gpadl_handle);
+	if (sc->hn_rxbuf_gpadl != 0) {
 		/*
-		 * If we failed here, we might as well return and have a leak 
-		 * rather than continue and a bugchk
+		 * Disconnect RXBUF from primary channel.
 		 */
+		ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
+		    sc->hn_rxbuf_gpadl);
 		if (ret != 0) {
+			if_printf(sc->hn_ifp,
+			    "rxbuf disconn failed: %d\n", ret);
 			return (ret);
 		}
-		net_dev->rx_buf_gpadl_handle = 0;
+		sc->hn_rxbuf_gpadl = 0;
 	}
-
-	if (net_dev->rx_buf) {
-		/* Free up the receive buffer */
-		hyperv_dmamem_free(&net_dev->rxbuf_dma, net_dev->rx_buf);
-		net_dev->rx_buf = NULL;
-	}
-
 	return (ret);
 }
 
@@ -583,6 +564,7 @@ hv_nv_connect_to_vsp(struct hn_softc *sc
 	device_t dev = sc->hn_dev;
 	struct ifnet *ifp = sc->hn_ifp;
 	struct hn_nvs_ndis_init ndis;
+	int rxbuf_size;
 
 	net_dev = hv_nv_get_outbound_net_device(sc);
 
@@ -637,12 +619,12 @@ hv_nv_connect_to_vsp(struct hn_softc *sc
 
 	/* Post the big receive buffer to NetVSP */
 	if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_2)
-		net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
+		rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
 	else
-		net_dev->rx_buf_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);
+	ret = hv_nv_init_rx_buffer_with_net_vsp(sc, rxbuf_size);
 	if (ret == 0)
 		ret = hv_nv_init_send_buffer_with_net_vsp(sc);
 
@@ -654,10 +636,10 @@ cleanup:
  * Net VSC disconnect from VSP
  */
 static void
-hv_nv_disconnect_from_vsp(netvsc_dev *net_dev)
+hv_nv_disconnect_from_vsp(struct hn_softc *sc)
 {
-	hv_nv_destroy_rx_buffer(net_dev);
-	hv_nv_destroy_send_buffer(net_dev);
+	hv_nv_destroy_rx_buffer(sc);
+	hv_nv_destroy_send_buffer(sc->net_dev);
 }
 
 void
@@ -731,17 +713,14 @@ cleanup:
 int
 hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
 {
-	netvsc_dev *net_dev = sc->net_dev;;
 	
-	hv_nv_disconnect_from_vsp(net_dev);
-
-	/* At this point, no one should be accessing net_dev except in here */
+	hv_nv_disconnect_from_vsp(sc);
 
 	/* Now, we can close the channel safely */
 
 	vmbus_chan_close(sc->hn_prichan);
 
-	free(net_dev, M_NETVSC);
+	free(sc->net_dev, M_NETVSC);
 
 	return (0);
 }
@@ -865,7 +844,7 @@ hv_nv_on_receive(netvsc_dev *net_dev, st
 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
 	for (i = 0; i < count; i++) {
 		hv_rf_on_receive(net_dev, rxr,
-		    (const uint8_t *)net_dev->rx_buf + pkt->cp_rxbuf[i].rb_ofs,
+		    rxr->hn_rxbuf + pkt->cp_rxbuf[i].rb_ofs,
 		    pkt->cp_rxbuf[i].rb_len);
 	}
 	

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Aug 19 05:30:39 2016	(r304446)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Aug 19 05:43:28 2016	(r304447)
@@ -227,16 +227,9 @@ typedef struct netvsc_dev_ {
 	unsigned long				bitsmap_words;
 	unsigned long				*send_section_bitsmap;
 
-	/* Receive buffer allocated by us but managed by NetVSP */
-	void					*rx_buf;
-	uint32_t				rx_buf_size;
-	uint32_t				rx_buf_gpadl_handle;
-	uint32_t				rx_section_count;
-
 	/* Holds rndis device info */
 	void					*extension;
 
-	struct hyperv_dma			rxbuf_dma;
 	struct hyperv_dma			txbuf_dma;
 } netvsc_dev;
 
@@ -286,6 +279,7 @@ struct hn_rx_ring {
 	struct ifnet	*hn_ifp;
 	struct hn_tx_ring *hn_txr;
 	void		*hn_rdbuf;
+	uint8_t		*hn_rxbuf;	/* shadow sc->hn_rxbuf */
 	int		hn_rx_idx;
 
 	/* Trust csum verification on host side */
@@ -395,8 +389,15 @@ typedef struct hn_softc {
 	struct sysctl_oid *hn_rx_sysctl_tree;
 	struct vmbus_xact_ctx *hn_xact;
 	uint32_t	hn_nvs_ver;
+
+	uint32_t		hn_flags;
+	void			*hn_rxbuf;
+	uint32_t		hn_rxbuf_gpadl;
+	struct hyperv_dma	hn_rxbuf_dma;
 } hn_softc_t;
 
+#define HN_FLAG_RXBUF_CONNECTED		0x0001
+
 /*
  * Externs
  */

Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Aug 19 05:30:39 2016	(r304446)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Aug 19 05:43:28 2016	(r304447)
@@ -342,7 +342,7 @@ static void hn_start_taskfunc(void *, in
 static void hn_start_txeof_taskfunc(void *, int);
 static void hn_stop_tx_tasks(struct hn_softc *);
 static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
-static void hn_create_rx_data(struct hn_softc *sc, int);
+static int hn_create_rx_data(struct hn_softc *sc, int);
 static void hn_destroy_rx_data(struct hn_softc *sc);
 static void hn_set_tx_chimney_size(struct hn_softc *, int);
 static void hn_channel_attach(struct hn_softc *, struct vmbus_channel *);
@@ -504,7 +504,9 @@ netvsc_attach(device_t dev)
 	error = hn_create_tx_data(sc, tx_ring_cnt);
 	if (error)
 		goto failed;
-	hn_create_rx_data(sc, ring_cnt);
+	error = hn_create_rx_data(sc, ring_cnt);
+	if (error)
+		goto failed;
 
 	/*
 	 * Associate the first TX/RX ring w/ the primary channel.
@@ -2176,7 +2178,7 @@ hn_check_iplen(const struct mbuf *m, int
 	return ip->ip_p;
 }
 
-static void
+static int
 hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
 {
 	struct sysctl_oid_list *child;
@@ -2189,6 +2191,22 @@ hn_create_rx_data(struct hn_softc *sc, i
 #endif
 	int i;
 
+	/*
+	 * Create RXBUF for reception.
+	 *
+	 * NOTE:
+	 * - It is shared by all channels.
+	 * - A large enough buffer is allocated, certain version of NVSes
+	 *   may further limit the usable space.
+	 */
+	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
+	    PAGE_SIZE, 0, NETVSC_RECEIVE_BUFFER_SIZE, &sc->hn_rxbuf_dma,
+	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
+	if (sc->hn_rxbuf == NULL) {
+		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
+		return (ENOMEM);
+	}
+
 	sc->hn_rx_ring_cnt = ring_cnt;
 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
 
@@ -2225,6 +2243,7 @@ hn_create_rx_data(struct hn_softc *sc, i
 			rxr->hn_txr = &sc->hn_tx_ring[i];
 		rxr->hn_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK);
 		rxr->hn_rx_idx = i;
+		rxr->hn_rxbuf = sc->hn_rxbuf;
 
 		/*
 		 * Initialize LRO.
@@ -2331,6 +2350,8 @@ hn_create_rx_data(struct hn_softc *sc, i
 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
+
+	return (0);
 }
 
 static void
@@ -2354,6 +2375,11 @@ hn_destroy_rx_data(struct hn_softc *sc)
 
 	sc->hn_rx_ring_cnt = 0;
 	sc->hn_rx_ring_inuse = 0;
+
+	if (sc->hn_rxbuf != NULL) {
+		hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
+		sc->hn_rxbuf = NULL;
+	}
 }
 
 static int



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608190543.u7J5hSJi055331>