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:
parent
d981413bcb
commit
852710e6db
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=304447
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user