1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

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
This commit is contained in:
Sepherosa Ziehau 2016-08-19 05:43:28 +00:00
parent d981413bcb
commit 852710e6db
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=304447
3 changed files with 68 additions and 62 deletions

View File

@ -59,9 +59,9 @@ MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
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 *net_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 hn_softc *sc)
* 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 hn_softc *sc)
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 hn_softc *sc)
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 @@ hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
* 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_dev)
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 @@ hv_nv_connect_to_vsp(struct hn_softc *sc)
* 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 @@ hv_nv_on_device_add(struct hn_softc *sc, void *additional_info,
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, struct hn_rx_ring *rxr,
/* 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);
}

View File

@ -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
*/

View File

@ -342,7 +342,7 @@ static void hn_start_taskfunc(void *, int);
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 hoff)
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, int ring_cnt)
#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, int ring_cnt)
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, int ring_cnt)
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