Date: Wed, 21 Sep 2016 05:56:47 +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: r306072 - in head/sys/dev/hyperv: include vmbus Message-ID: <201609210556.u8L5ulQc094633@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: sephe Date: Wed Sep 21 05:56:47 2016 New Revision: 306072 URL: https://svnweb.freebsd.org/changeset/base/306072 Log: hyperv/vmbus: Allow bufrings preallocation. The assumption that the channel is only opened upon synthetic device attach time no longer holds, e.g. Hyper-V network device MTU changes. We have to allow device drivers to preallocate bufrings, e.g. in attach DEVMETHOD, to prevent bufring allocation failure once the system memory is fragmented after running for a while. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7960 Modified: head/sys/dev/hyperv/include/vmbus.h head/sys/dev/hyperv/vmbus/vmbus_chan.c Modified: head/sys/dev/hyperv/include/vmbus.h ============================================================================== --- head/sys/dev/hyperv/include/vmbus.h Wed Sep 21 05:44:13 2016 (r306071) +++ head/sys/dev/hyperv/include/vmbus.h Wed Sep 21 05:56:47 2016 (r306072) @@ -108,6 +108,13 @@ struct vmbus_chanpkt_rxbuf { struct vmbus_rxbuf_desc cp_rxbuf[]; } __packed; +struct vmbus_chan_br { + void *cbr; + bus_addr_t cbr_paddr; + int cbr_txsz; + int cbr_rxsz; +}; + struct vmbus_channel; struct hyperv_guid; @@ -122,6 +129,9 @@ vmbus_get_channel(device_t dev) int vmbus_chan_open(struct vmbus_channel *chan, int txbr_size, int rxbr_size, const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg); +int vmbus_chan_open_br(struct vmbus_channel *chan, + const struct vmbus_chan_br *cbr, const void *udata, + int udlen, vmbus_chan_callback_t cb, void *cbarg); void vmbus_chan_close(struct vmbus_channel *chan); int vmbus_chan_gpadl_connect(struct vmbus_channel *chan, Modified: head/sys/dev/hyperv/vmbus/vmbus_chan.c ============================================================================== --- head/sys/dev/hyperv/vmbus/vmbus_chan.c Wed Sep 21 05:44:13 2016 (r306071) +++ head/sys/dev/hyperv/vmbus/vmbus_chan.c Wed Sep 21 05:56:47 2016 (r306072) @@ -196,13 +196,45 @@ int vmbus_chan_open(struct vmbus_channel *chan, int txbr_size, int rxbr_size, const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg) { + struct vmbus_chan_br cbr; + int error; + + /* + * Allocate the TX+RX bufrings. + */ + KASSERT(chan->ch_bufring == NULL, ("bufrings are allocated")); + chan->ch_bufring = hyperv_dmamem_alloc(bus_get_dma_tag(chan->ch_dev), + PAGE_SIZE, 0, txbr_size + rxbr_size, &chan->ch_bufring_dma, + BUS_DMA_WAITOK); + if (chan->ch_bufring == NULL) { + device_printf(chan->ch_dev, "bufring allocation failed\n"); + return (ENOMEM); + } + + cbr.cbr = chan->ch_bufring; + cbr.cbr_paddr = chan->ch_bufring_dma.hv_paddr; + cbr.cbr_txsz = txbr_size; + cbr.cbr_rxsz = rxbr_size; + + error = vmbus_chan_open_br(chan, &cbr, udata, udlen, cb, cbarg); + if (error) { + hyperv_dmamem_free(&chan->ch_bufring_dma, chan->ch_bufring); + chan->ch_bufring = NULL; + } + return (error); +} + +int +vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, + const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg) +{ struct vmbus_softc *sc = chan->ch_vmbus; const struct vmbus_chanmsg_chopen_resp *resp; const struct vmbus_message *msg; struct vmbus_chanmsg_chopen *req; struct vmbus_msghc *mh; uint32_t status; - int error; + int error, txbr_size, rxbr_size; uint8_t *br; if (udlen > VMBUS_CHANMSG_CHOPEN_UDATA_SIZE) { @@ -210,11 +242,20 @@ vmbus_chan_open(struct vmbus_channel *ch "invalid udata len %d for chan%u\n", udlen, chan->ch_id); return EINVAL; } + + br = cbr->cbr; + txbr_size = cbr->cbr_txsz; + rxbr_size = cbr->cbr_rxsz; KASSERT((txbr_size & PAGE_MASK) == 0, ("send bufring size is not multiple page")); KASSERT((rxbr_size & PAGE_MASK) == 0, ("recv bufring size is not multiple page")); + /* + * Zero out the TX/RX bufrings, in case that they were used before. + */ + memset(br, 0, txbr_size + rxbr_size); + if (atomic_testandset_int(&chan->ch_stflags, VMBUS_CHAN_ST_OPENED_SHIFT)) panic("double-open chan%u", chan->ch_id); @@ -230,20 +271,6 @@ vmbus_chan_open(struct vmbus_channel *ch else TASK_INIT(&chan->ch_task, 0, vmbus_chan_task_nobatch, chan); - /* - * Allocate the TX+RX bufrings. - * XXX should use ch_dev dtag - */ - br = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), - PAGE_SIZE, 0, txbr_size + rxbr_size, &chan->ch_bufring_dma, - BUS_DMA_WAITOK | BUS_DMA_ZERO); - if (br == NULL) { - device_printf(sc->vmbus_dev, "bufring allocation failed\n"); - error = ENOMEM; - goto failed; - } - chan->ch_bufring = br; - /* TX bufring comes first */ vmbus_txbr_setup(&chan->ch_txbr, br, txbr_size); /* RX bufring immediately follows TX bufring */ @@ -255,7 +282,7 @@ vmbus_chan_open(struct vmbus_channel *ch /* * Connect the bufrings, both RX and TX, to this channel. */ - error = vmbus_chan_gpadl_connect(chan, chan->ch_bufring_dma.hv_paddr, + error = vmbus_chan_gpadl_connect(chan, cbr->cbr_paddr, txbr_size + rxbr_size, &chan->ch_bufring_gpadl); if (error) { device_printf(sc->vmbus_dev, @@ -316,10 +343,6 @@ failed: vmbus_chan_gpadl_disconnect(chan, chan->ch_bufring_gpadl); chan->ch_bufring_gpadl = 0; } - if (chan->ch_bufring != NULL) { - hyperv_dmamem_free(&chan->ch_bufring_dma, chan->ch_bufring); - chan->ch_bufring = NULL; - } atomic_clear_int(&chan->ch_stflags, VMBUS_CHAN_ST_OPENED); return error; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201609210556.u8L5ulQc094633>