summaryrefslogtreecommitdiff
path: root/sys/dev/hyperv
diff options
context:
space:
mode:
authornonaka <nonaka@NetBSD.org>2019-12-10 12:20:20 +0000
committernonaka <nonaka@NetBSD.org>2019-12-10 12:20:20 +0000
commitb4ad7757ae81d5f92df482b9eeb41d06bac53ce9 (patch)
tree559bf02b62003753d5dbf190ed30c0f1f568cec6 /sys/dev/hyperv
parenta3e2ddaaabbede72e3ad7cbbeafa5a99cd5b0ed3 (diff)
hvn(4) can be added and deleted dynamically.
Diffstat (limited to 'sys/dev/hyperv')
-rw-r--r--sys/dev/hyperv/hyperv_common.c13
-rw-r--r--sys/dev/hyperv/hypervvar.h6
-rw-r--r--sys/dev/hyperv/if_hvn.c57
-rw-r--r--sys/dev/hyperv/vmbus.c360
-rw-r--r--sys/dev/hyperv/vmbusvar.h35
5 files changed, 262 insertions, 209 deletions
diff --git a/sys/dev/hyperv/hyperv_common.c b/sys/dev/hyperv/hyperv_common.c
index 56c3b6e9275..4347dc47f86 100644
--- a/sys/dev/hyperv/hyperv_common.c
+++ b/sys/dev/hyperv/hyperv_common.c
@@ -1,4 +1,4 @@
-/* $NetBSD: hyperv_common.c,v 1.4 2019/12/07 11:45:45 nonaka Exp $ */
+/* $NetBSD: hyperv_common.c,v 1.5 2019/12/10 12:20:20 nonaka Exp $ */
/*-
* Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hyperv_common.c,v 1.4 2019/12/07 11:45:45 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hyperv_common.c,v 1.5 2019/12/10 12:20:20 nonaka Exp $");
#include "hyperv.h"
@@ -111,17 +111,18 @@ hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz)
*/
void *
hyperv_dma_alloc(bus_dma_tag_t dmat, struct hyperv_dma *dma, bus_size_t size,
- bus_size_t alignment, bus_size_t boundary, int nsegs)
+ bus_size_t alignment, bus_size_t boundary, int nsegs, int flags)
{
- const int kmemflags = cold ? KM_NOSLEEP : KM_SLEEP;
- const int dmaflags = cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
+ const int waitok = (flags & HYPERV_DMA_NOSLEEP) != HYPERV_DMA_NOSLEEP;
+ const int kmemflags = waitok ? KM_SLEEP: KM_NOSLEEP;
+ const int dmaflags = waitok ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT;
int rseg, error;
KASSERT(dma != NULL);
KASSERT(dma->segs == NULL);
KASSERT(nsegs > 0);
- dma->segs = kmem_zalloc(sizeof(*dma->segs) * nsegs, kmemflags);
+ dma->segs = kmem_intr_zalloc(sizeof(*dma->segs) * nsegs, kmemflags);
if (dma->segs == NULL)
return NULL;
diff --git a/sys/dev/hyperv/hypervvar.h b/sys/dev/hyperv/hypervvar.h
index 7f7759cfb81..2ee80974be5 100644
--- a/sys/dev/hyperv/hypervvar.h
+++ b/sys/dev/hyperv/hypervvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: hypervvar.h,v 1.3 2019/12/07 11:45:45 nonaka Exp $ */
+/* $NetBSD: hypervvar.h,v 1.4 2019/12/10 12:20:20 nonaka Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
@@ -108,8 +108,10 @@ hyperv_dma_get_paddr(struct hyperv_dma *dma)
return dma->map->dm_segs[0].ds_addr;
}
+#define HYPERV_DMA_SLEEPOK 0
+#define HYPERV_DMA_NOSLEEP __BIT(0)
void *hyperv_dma_alloc(bus_dma_tag_t, struct hyperv_dma *, bus_size_t,
- bus_size_t, bus_size_t, int);
+ bus_size_t, bus_size_t, int, int);
void hyperv_dma_free(bus_dma_tag_t, struct hyperv_dma *);
#endif /* _KERNEL */
diff --git a/sys/dev/hyperv/if_hvn.c b/sys/dev/hyperv/if_hvn.c
index bb15f6c7e66..5736a1d97b6 100644
--- a/sys/dev/hyperv/if_hvn.c
+++ b/sys/dev/hyperv/if_hvn.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_hvn.c,v 1.12 2019/12/10 11:19:25 nonaka Exp $ */
+/* $NetBSD: if_hvn.c,v 1.13 2019/12/10 12:20:20 nonaka Exp $ */
/* $OpenBSD: if_hvn.c,v 1.39 2018/03/11 14:31:34 mikeb Exp $ */
/*-
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_hvn.c,v 1.12 2019/12/10 11:19:25 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_hvn.c,v 1.13 2019/12/10 12:20:20 nonaka Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -249,8 +249,6 @@ hvn_attach(device_t parent, device_t self, void *aux)
aprint_naive("\n");
aprint_normal(": Hyper-V NetVSC\n");
- strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
-
if (hvn_nvs_attach(sc)) {
aprint_error_dev(self, "failed to init NVSP\n");
return;
@@ -263,9 +261,10 @@ hvn_attach(device_t parent, device_t self, void *aux)
if (hvn_tx_ring_create(sc)) {
aprint_error_dev(self, "failed to create Tx ring\n");
- goto fail1;
+ goto fail2;
}
+ strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = hvn_ioctl;
@@ -300,14 +299,14 @@ hvn_attach(device_t parent, device_t self, void *aux)
error = if_initialize(ifp);
if (error) {
aprint_error_dev(self, "if_initialize failed(%d)\n", error);
- goto fail2;
+ goto fail3;
}
sc->sc_ipq = if_percpuq_create(ifp);
if_deferred_start_init(ifp, NULL);
if (hvn_rndis_attach(sc)) {
aprint_error_dev(self, "failed to init RNDIS\n");
- goto fail1;
+ goto fail3;
}
aprint_normal_dev(self, "NVS %d.%d NDIS %d.%d\n",
@@ -316,13 +315,13 @@ hvn_attach(device_t parent, device_t self, void *aux)
if (hvn_set_capabilities(sc)) {
aprint_error_dev(self, "failed to setup offloading\n");
- goto fail2;
+ goto fail4;
}
if (hvn_get_lladdr(sc, enaddr)) {
aprint_error_dev(self,
"failed to obtain an ethernet address\n");
- goto fail2;
+ goto fail4;
}
aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(enaddr));
@@ -337,10 +336,11 @@ hvn_attach(device_t parent, device_t self, void *aux)
SET(sc->sc_flags, HVN_SCF_ATTACHED);
return;
-fail2: hvn_rndis_detach(sc);
-fail1: hvn_rx_ring_destroy(sc);
- hvn_tx_ring_destroy(sc);
- hvn_nvs_detach(sc);
+fail4: hvn_rndis_detach(sc);
+ if_percpuq_destroy(sc->sc_ipq);
+fail3: hvn_tx_ring_destroy(sc);
+fail2: hvn_rx_ring_destroy(sc);
+fail1: hvn_nvs_detach(sc);
}
static int
@@ -352,7 +352,8 @@ hvn_detach(device_t self, int flags)
if (!ISSET(sc->sc_flags, HVN_SCF_ATTACHED))
return 0;
- hvn_stop(ifp, 1);
+ if (ifp->if_flags & IFF_RUNNING)
+ hvn_stop(ifp, 1);
pmf_device_deregister(self);
@@ -693,7 +694,8 @@ hvn_rx_ring_create(struct hvn_softc *sc)
else
sc->sc_rx_size = 16 * 1024 * 1024; /* 16MB */
sc->sc_rx_ring = hyperv_dma_alloc(sc->sc_dmat, &sc->sc_rx_dma,
- sc->sc_rx_size, PAGE_SIZE, PAGE_SIZE, sc->sc_rx_size / PAGE_SIZE);
+ sc->sc_rx_size, PAGE_SIZE, PAGE_SIZE, sc->sc_rx_size / PAGE_SIZE,
+ HYPERV_DMA_SLEEPOK);
if (sc->sc_rx_ring == NULL) {
DPRINTF("%s: failed to allocate Rx ring buffer\n",
device_xname(sc->sc_dev));
@@ -735,7 +737,7 @@ hvn_rx_ring_create(struct hvn_softc *sc)
sc->sc_rx_hndl = 0;
}
if (sc->sc_rx_ring) {
- kmem_free(sc->sc_rx_ring, sc->sc_rx_size);
+ hyperv_dma_free(sc->sc_dmat, &sc->sc_rx_dma);
sc->sc_rx_ring = NULL;
}
return -1;
@@ -761,10 +763,9 @@ hvn_rx_ring_destroy(struct hvn_softc *sc)
delay(100);
vmbus_handle_free(sc->sc_chan, sc->sc_rx_hndl);
-
sc->sc_rx_hndl = 0;
- kmem_free(sc->sc_rx_ring, sc->sc_rx_size);
+ hyperv_dma_free(sc->sc_dmat, &sc->sc_rx_dma);
sc->sc_rx_ring = NULL;
return 0;
@@ -854,25 +855,25 @@ hvn_tx_ring_destroy(struct hvn_softc *sc)
txd->txd_dmap = NULL;
if (txd->txd_buf == NULL)
continue;
- m_free(txd->txd_buf);
+ m_freem(txd->txd_buf);
txd->txd_buf = NULL;
}
- if (sc->sc_tx_rmap) {
+ if (sc->sc_tx_rmap != NULL) {
bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap,
- 0, txd->txd_dmap->dm_mapsize,
+ 0, sc->sc_tx_rmap->dm_mapsize,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
+ sc->sc_tx_rmap = NULL;
}
- if (sc->sc_tx_msgs) {
+ if (sc->sc_tx_msgs != NULL) {
size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
bus_dmamem_unmap(sc->sc_dmat, sc->sc_tx_msgs,
msgsize * HVN_TX_DESC);
bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1);
+ sc->sc_tx_msgs = NULL;
}
- sc->sc_tx_rmap = NULL;
- sc->sc_tx_msgs = NULL;
}
static int
@@ -1414,6 +1415,10 @@ hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
"RNDIS operation %u send error %d\n", hdr->rm_type, rv);
return rv;
}
+ if (vmbus_channel_is_revoked(sc->sc_chan)) {
+ /* No response */
+ return 0;
+ }
bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
BUS_DMASYNC_POSTWRITE);
@@ -1843,4 +1848,8 @@ hvn_rndis_detach(struct hvn_softc *sc)
device_xname(sc->sc_dev), rv);
}
hvn_free_cmd(sc, rc);
+
+ mutex_destroy(&sc->sc_cntl_sqlck);
+ mutex_destroy(&sc->sc_cntl_cqlck);
+ mutex_destroy(&sc->sc_cntl_fqlck);
}
diff --git a/sys/dev/hyperv/vmbus.c b/sys/dev/hyperv/vmbus.c
index 41ef07394d6..e410697942f 100644
--- a/sys/dev/hyperv/vmbus.c
+++ b/sys/dev/hyperv/vmbus.c
@@ -1,4 +1,4 @@
-/* $NetBSD: vmbus.c,v 1.7 2019/12/07 11:45:45 nonaka Exp $ */
+/* $NetBSD: vmbus.c,v 1.8 2019/12/10 12:20:20 nonaka Exp $ */
/* $OpenBSD: hyperv.c,v 1.43 2017/06/27 13:56:15 mikeb Exp $ */
/*-
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.7 2019/12/07 11:45:45 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.8 2019/12/10 12:20:20 nonaka Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.7 2019/12/07 11:45:45 nonaka Exp $");
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/kmem.h>
+#include <sys/kthread.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/xcall.h>
@@ -62,6 +63,7 @@ __KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.7 2019/12/07 11:45:45 nonaka Exp $");
#define HCF_NOREPLY 0x0004
static void vmbus_attach_deferred(device_t);
+static int vmbus_attach_print(void *, const char *);
static int vmbus_alloc_dma(struct vmbus_softc *);
static void vmbus_free_dma(struct vmbus_softc *);
static int vmbus_init_interrupts(struct vmbus_softc *);
@@ -92,16 +94,22 @@ static void vmbus_channel_delivered(struct vmbus_softc *,
struct vmbus_chanmsg_hdr *);
static int vmbus_channel_scan(struct vmbus_softc *);
static void vmbus_channel_cpu_default(struct vmbus_channel *);
-static void vmbus_process_offer(struct vmbus_softc *, struct vmbus_offer *);
+static void vmbus_process_offer(struct vmbus_softc *,
+ struct vmbus_chanmsg_choffer *);
+static void vmbus_process_rescind(struct vmbus_softc *,
+ struct vmbus_chanmsg_chrescind *);
static struct vmbus_channel *
vmbus_channel_lookup(struct vmbus_softc *, uint32_t);
static int vmbus_channel_ring_create(struct vmbus_channel *, uint32_t);
static void vmbus_channel_ring_destroy(struct vmbus_channel *);
+static void vmbus_channel_detach(struct vmbus_channel *);
static void vmbus_channel_pause(struct vmbus_channel *);
static uint32_t vmbus_channel_unpause(struct vmbus_channel *);
static uint32_t vmbus_channel_ready(struct vmbus_channel *);
-static int vmbus_attach_icdevs(struct vmbus_softc *);
-static int vmbus_attach_devices(struct vmbus_softc *);
+static void vmbus_devq_enqueue(struct vmbus_softc *, int,
+ struct vmbus_channel *);
+static void vmbus_process_devq(void *);
+static void vmbus_devq_thread(void *);
static struct vmbus_softc *vmbus_sc;
@@ -290,12 +298,6 @@ vmbus_attach(struct vmbus_softc *sc)
if (vmbus_channel_scan(sc))
goto cleanup;
- /* Attach heartbeat, KVP and other "internal" services */
- vmbus_attach_icdevs(sc);
-
- /* Attach devices with external drivers */
- vmbus_attach_devices(sc);
-
config_interrupts(sc->sc_dev, vmbus_attach_deferred);
return 0;
@@ -339,18 +341,18 @@ vmbus_alloc_dma(struct vmbus_softc *sc)
pd = &sc->sc_percpu[cpu_index(ci)];
pd->simp = hyperv_dma_alloc(sc->sc_dmat, &pd->simp_dma,
- PAGE_SIZE, PAGE_SIZE, 0, 1);
+ PAGE_SIZE, PAGE_SIZE, 0, 1, HYPERV_DMA_SLEEPOK);
if (pd->simp == NULL)
return ENOMEM;
pd->siep = hyperv_dma_alloc(sc->sc_dmat, &pd->siep_dma,
- PAGE_SIZE, PAGE_SIZE, 0, 1);
+ PAGE_SIZE, PAGE_SIZE, 0, 1, HYPERV_DMA_SLEEPOK);
if (pd->siep == NULL)
return ENOMEM;
}
sc->sc_events = hyperv_dma_alloc(sc->sc_dmat, &sc->sc_events_dma,
- PAGE_SIZE, PAGE_SIZE, 0, 1);
+ PAGE_SIZE, PAGE_SIZE, 0, 1, HYPERV_DMA_SLEEPOK);
if (sc->sc_events == NULL)
return ENOMEM;
sc->sc_wevents = (u_long *)sc->sc_events;
@@ -358,7 +360,8 @@ vmbus_alloc_dma(struct vmbus_softc *sc)
for (i = 0; i < __arraycount(sc->sc_monitor); i++) {
sc->sc_monitor[i] = hyperv_dma_alloc(sc->sc_dmat,
- &sc->sc_monitor_dma[i], PAGE_SIZE, PAGE_SIZE, 0, 1);
+ &sc->sc_monitor_dma[i], PAGE_SIZE, PAGE_SIZE, 0, 1,
+ HYPERV_DMA_SLEEPOK);
if (sc->sc_monitor[i] == NULL)
return ENOMEM;
}
@@ -851,28 +854,15 @@ vmbus_channel_response(struct vmbus_softc *sc, struct vmbus_chanmsg_hdr *rsphdr)
static void
vmbus_channel_offer(struct vmbus_softc *sc, struct vmbus_chanmsg_hdr *hdr)
{
- struct vmbus_offer *co;
-
- co = kmem_intr_zalloc(sizeof(*co), KM_NOSLEEP);
- if (co == NULL) {
- device_printf(sc->sc_dev, "couldn't allocate offer\n");
- return;
- }
-
- memcpy(&co->co_chan, hdr, sizeof(co->co_chan));
- mutex_enter(&sc->sc_offer_lock);
- SIMPLEQ_INSERT_TAIL(&sc->sc_offers, co, co_entry);
- mutex_exit(&sc->sc_offer_lock);
+ vmbus_process_offer(sc, (struct vmbus_chanmsg_choffer *)hdr);
}
static void
vmbus_channel_rescind(struct vmbus_softc *sc, struct vmbus_chanmsg_hdr *hdr)
{
- const struct vmbus_chanmsg_chrescind *cmd;
- cmd = (const struct vmbus_chanmsg_chrescind *)hdr;
- device_printf(sc->sc_dev, "revoking channel %u\n", cmd->chm_chanid);
+ vmbus_process_rescind(sc, (struct vmbus_chanmsg_chrescind *)hdr);
}
static void
@@ -880,7 +870,7 @@ vmbus_channel_delivered(struct vmbus_softc *sc, struct vmbus_chanmsg_hdr *hdr)
{
atomic_or_32(&sc->sc_flags, VMBUS_SCFLAG_OFFERS_DELIVERED);
- wakeup(&sc->sc_offers);
+ wakeup(&sc->sc_devq);
}
static void
@@ -935,10 +925,20 @@ vmbus_channel_scan(struct vmbus_softc *sc)
{
struct vmbus_chanmsg_hdr hdr;
struct vmbus_chanmsg_choffer rsp;
- struct vmbus_offer *co;
- SIMPLEQ_INIT(&sc->sc_offers);
- mutex_init(&sc->sc_offer_lock, MUTEX_DEFAULT, IPL_NET);
+ TAILQ_INIT(&sc->sc_channels);
+ mutex_init(&sc->sc_channel_lock, MUTEX_DEFAULT, IPL_NET);
+
+ SIMPLEQ_INIT(&sc->sc_devq);
+ mutex_init(&sc->sc_devq_lock, MUTEX_DEFAULT, IPL_NET);
+ cv_init(&sc->sc_devq_cv, "hvdevqcv");
+
+ if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
+ vmbus_devq_thread, sc, NULL, "hvoffer") != 0) {
+ DPRINTF("%s: failed to create offer thread\n",
+ device_xname(sc->sc_dev));
+ return -1;
+ }
memset(&hdr, 0, sizeof(hdr));
hdr.chm_type = VMBUS_CHANMSG_CHREQUEST;
@@ -950,23 +950,11 @@ vmbus_channel_scan(struct vmbus_softc *sc)
}
vmbus_wait(sc, vmbus_channel_scan_done, (struct vmbus_msg *)&hdr,
- &sc->sc_offers, "hvscan");
-
- TAILQ_INIT(&sc->sc_channels);
- mutex_init(&sc->sc_channel_lock, MUTEX_DEFAULT, IPL_NET);
-
- mutex_enter(&sc->sc_offer_lock);
- while (!SIMPLEQ_EMPTY(&sc->sc_offers)) {
- co = SIMPLEQ_FIRST(&sc->sc_offers);
- SIMPLEQ_REMOVE_HEAD(&sc->sc_offers, co_entry);
- mutex_exit(&sc->sc_offer_lock);
+ &sc->sc_devq, "hvscan");
- vmbus_process_offer(sc, co);
- kmem_free(co, sizeof(*co));
-
- mutex_enter(&sc->sc_offer_lock);
- }
- mutex_exit(&sc->sc_offer_lock);
+ mutex_enter(&sc->sc_devq_lock);
+ vmbus_process_devq(sc);
+ mutex_exit(&sc->sc_devq_lock);
return 0;
}
@@ -976,10 +964,10 @@ vmbus_channel_alloc(struct vmbus_softc *sc)
{
struct vmbus_channel *ch;
- ch = kmem_zalloc(sizeof(*ch), cold ? KM_NOSLEEP : KM_SLEEP);
+ ch = kmem_intr_zalloc(sizeof(*ch), KM_NOSLEEP);
ch->ch_monprm = hyperv_dma_alloc(sc->sc_dmat, &ch->ch_monprm_dma,
- sizeof(*ch->ch_monprm), 8, 0, 1);
+ sizeof(*ch->ch_monprm), 8, 0, 1, HYPERV_DMA_NOSLEEP);
if (ch->ch_monprm == NULL) {
device_printf(sc->sc_dev, "monprm alloc failed\n");
kmem_free(ch, sizeof(*ch));
@@ -1011,7 +999,8 @@ vmbus_channel_free(struct vmbus_channel *ch)
hyperv_dma_free(sc->sc_dmat, &ch->ch_monprm_dma);
mutex_destroy(&ch->ch_subchannel_lock);
/* XXX ch_evcnt */
- softint_disestablish(ch->ch_taskq);
+ if (ch->ch_taskq != NULL)
+ softint_disestablish(ch->ch_taskq);
kmem_free(ch, sizeof(*ch));
}
@@ -1061,8 +1050,8 @@ vmbus_channel_add(struct vmbus_channel *nch)
KASSERT(!VMBUS_CHAN_ISPRIMARY(nch));
KASSERT(ch != NULL);
- refs = atomic_add_int_nv(&nch->ch_refs, 1);
- KASSERT(refs == 1);
+ refs = atomic_inc_uint_nv(&nch->ch_refs);
+ KASSERT(refs == 2);
nch->ch_primary_channel = ch;
nch->ch_dev = ch->ch_dev;
@@ -1102,7 +1091,7 @@ vmbus_channel_cpu_rr(struct vmbus_channel *ch)
static uint32_t vmbus_channel_nextcpu;
int cpu;
- cpu = atomic_add_32_nv(&vmbus_channel_nextcpu, 1) % ncpu;
+ cpu = atomic_inc_32_nv(&vmbus_channel_nextcpu) % ncpu;
vmbus_channel_cpu_set(ch, cpu);
}
@@ -1118,15 +1107,23 @@ vmbus_channel_cpu_default(struct vmbus_channel *ch)
vmbus_channel_cpu_set(ch, 0);
}
+bool
+vmbus_channel_is_revoked(struct vmbus_channel *ch)
+{
+
+ return (ch->ch_flags & CHF_REVOKED) ? true : false;
+}
+
+
static void
-vmbus_process_offer(struct vmbus_softc *sc, struct vmbus_offer *co)
+vmbus_process_offer(struct vmbus_softc *sc, struct vmbus_chanmsg_choffer *co)
{
struct vmbus_channel *ch;
ch = vmbus_channel_alloc(sc);
if (ch == NULL) {
device_printf(sc->sc_dev, "allocate channel %u failed\n",
- co->co_chan.chm_chanid);
+ co->chm_chanid);
return;
}
@@ -1137,48 +1134,75 @@ vmbus_process_offer(struct vmbus_softc *sc, struct vmbus_offer *co)
*/
ch->ch_flags |= CHF_BATCHED;
- hyperv_guid_sprint(&co->co_chan.chm_chtype, ch->ch_ident,
+ hyperv_guid_sprint(&co->chm_chtype, ch->ch_ident,
sizeof(ch->ch_ident));
ch->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
if (sc->sc_proto > VMBUS_VERSION_WS2008)
- ch->ch_monprm->mp_connid = co->co_chan.chm_connid;
+ ch->ch_monprm->mp_connid = co->chm_connid;
- if (co->co_chan.chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) {
- ch->ch_mgroup = co->co_chan.chm_montrig / VMBUS_MONTRIG_LEN;
- ch->ch_mindex = co->co_chan.chm_montrig % VMBUS_MONTRIG_LEN;
+ if (co->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) {
+ ch->ch_mgroup = co->chm_montrig / VMBUS_MONTRIG_LEN;
+ ch->ch_mindex = co->chm_montrig % VMBUS_MONTRIG_LEN;
ch->ch_flags |= CHF_MONITOR;
}
- ch->ch_id = co->co_chan.chm_chanid;
- ch->ch_subidx = co->co_chan.chm_subidx;
-
- memcpy(&ch->ch_type, &co->co_chan.chm_chtype, sizeof(ch->ch_type));
- memcpy(&ch->ch_inst, &co->co_chan.chm_chinst, sizeof(ch->ch_inst));
+ ch->ch_id = co->chm_chanid;
+ ch->ch_subidx = co->chm_subidx;
- if (VMBUS_CHAN_ISPRIMARY(ch)) {
- /* set primary channel mgmt wq */
- } else {
- /* set sub channel mgmt wq */
- }
+ memcpy(&ch->ch_type, &co->chm_chtype, sizeof(ch->ch_type));
+ memcpy(&ch->ch_inst, &co->chm_chinst, sizeof(ch->ch_inst));
if (vmbus_channel_add(ch) != 0) {
+ atomic_dec_uint(&ch->ch_refs);
vmbus_channel_free(ch);
return;
}
ch->ch_state = VMBUS_CHANSTATE_OFFERED;
+ vmbus_devq_enqueue(sc, VMBUS_DEV_TYPE_ATTACH, ch);
+
#ifdef HYPERV_DEBUG
printf("%s: channel %u: \"%s\"", device_xname(sc->sc_dev), ch->ch_id,
ch->ch_ident);
if (ch->ch_flags & CHF_MONITOR)
- printf(", monitor %u\n", co->co_chan.chm_montrig);
+ printf(", monitor %u\n", co->chm_montrig);
else
printf("\n");
#endif
}
+static void
+vmbus_process_rescind(struct vmbus_softc *sc,
+ struct vmbus_chanmsg_chrescind *cr)
+{
+ struct vmbus_channel *ch;
+
+ if (cr->chm_chanid > VMBUS_CHAN_MAX) {
+ device_printf(sc->sc_dev, "invalid revoked channel%u\n",
+ cr->chm_chanid);
+ return;
+ }
+
+ mutex_enter(&sc->sc_channel_lock);
+ ch = vmbus_channel_lookup(sc, cr->chm_chanid);
+ if (ch == NULL) {
+ mutex_exit(&sc->sc_channel_lock);
+ device_printf(sc->sc_dev, "channel%u is not offered\n",
+ cr->chm_chanid);
+ return;
+ }
+ TAILQ_REMOVE(&sc->sc_channels, ch, ch_entry);
+ mutex_exit(&sc->sc_channel_lock);
+
+ KASSERTMSG(!(ch->ch_flags & CHF_REVOKED),
+ "channel%u has already been revoked", ch->ch_id);
+ atomic_or_uint(&ch->ch_flags, CHF_REVOKED);
+
+ vmbus_channel_detach(ch);
+}
+
static int
vmbus_channel_release(struct vmbus_channel *ch)
{
@@ -1256,8 +1280,9 @@ vmbus_channel_ring_create(struct vmbus_channel *ch, uint32_t buflen)
buflen = roundup(buflen, PAGE_SIZE) + sizeof(struct vmbus_bufring);
ch->ch_ring_size = 2 * buflen;
+ /* page aligned memory */
ch->ch_ring = hyperv_dma_alloc(sc->sc_dmat, &ch->ch_ring_dma,
- ch->ch_ring_size, PAGE_SIZE, 0, 1); /* page aligned memory */
+ ch->ch_ring_size, PAGE_SIZE, 0, 1, HYPERV_DMA_SLEEPOK);
if (ch->ch_ring == NULL) {
device_printf(sc->sc_dev,
"failed to allocate channel ring\n");
@@ -1354,25 +1379,13 @@ vmbus_channel_detach(struct vmbus_channel *ch)
{
u_int refs;
- refs = atomic_add_int_nv(&ch->ch_refs, -1);
- if (refs == 1) {
- /* XXX on workqueue? */
- if (VMBUS_CHAN_ISPRIMARY(ch)) {
- vmbus_channel_release(ch);
- vmbus_channel_free(ch);
- } else {
- struct vmbus_channel *prich = ch->ch_primary_channel;
-
- vmbus_channel_release(ch);
-
- mutex_enter(&prich->ch_subchannel_lock);
- TAILQ_REMOVE(&prich->ch_subchannels, ch, ch_subentry);
- prich->ch_subchannel_count--;
- mutex_exit(&prich->ch_subchannel_lock);
- wakeup(prich);
+ KASSERTMSG(ch->ch_refs > 0, "channel%u: invalid refcnt %d",
+ ch->ch_id, ch->ch_refs);
- vmbus_channel_free(ch);
- }
+ refs = atomic_dec_uint_nv(&ch->ch_refs);
+ if (refs == 0) {
+ /* Detach the target channel. */
+ vmbus_devq_enqueue(ch->ch_sc, VMBUS_DEV_TYPE_DETACH, ch);
}
}
@@ -1908,7 +1921,7 @@ vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
}
}
- *handle = atomic_add_int_nv(&sc->sc_handle, 1);
+ *handle = atomic_inc_32_nv(&sc->sc_handle);
hdr->chm_hdr.chm_type = VMBUS_CHANMSG_GPADL_CONN;
hdr->chm_chanid = ch->ch_id;
@@ -1998,87 +2011,120 @@ vmbus_handle_free(struct vmbus_channel *ch, uint32_t handle)
}
}
-static int
-vmbus_attach_print(void *aux, const char *name)
+static void
+vmbus_devq_enqueue(struct vmbus_softc *sc, int type, struct vmbus_channel *ch)
{
- struct vmbus_attach_args *aa = aux;
+ struct vmbus_dev *vd;
- if (name)
- printf("\"%s\" at %s", aa->aa_ident, name);
+ vd = kmem_intr_zalloc(sizeof(*vd), KM_NOSLEEP);
+ if (vd == NULL) {
+ device_printf(sc->sc_dev, "failed to allocate devq\n");
+ return;
+ }
- return UNCONF;
+ vd->vd_type = type;
+ vd->vd_chan = ch;
+
+ mutex_enter(&sc->sc_devq_lock);
+ SIMPLEQ_INSERT_TAIL(&sc->sc_devq, vd, vd_entry);
+ cv_broadcast(&sc->sc_devq_cv);
+ mutex_exit(&sc->sc_devq_lock);
}
-static int
-vmbus_attach_icdevs(struct vmbus_softc *sc)
+static void
+vmbus_process_devq(void *arg)
{
- struct vmbus_dev *dv;
- struct vmbus_channel *ch;
+ struct vmbus_softc *sc = arg;
+ struct vmbus_dev *vd;
+ struct vmbus_channel *ch, *prich;
+
+ KASSERT(mutex_owned(&sc->sc_devq_lock));
+
+ while (!SIMPLEQ_EMPTY(&sc->sc_devq)) {
+ vd = SIMPLEQ_FIRST(&sc->sc_devq);
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_devq, vd_entry);
+ mutex_exit(&sc->sc_devq_lock);
+
+ switch (vd->vd_type) {
+ case VMBUS_DEV_TYPE_ATTACH:
+ ch = vd->vd_chan;
+ if (VMBUS_CHAN_ISPRIMARY(ch)) {
+ struct vmbus_attach_args vaa;
+
+ vaa.aa_type = &ch->ch_type;
+ vaa.aa_inst = &ch->ch_inst;
+ vaa.aa_ident = ch->ch_ident;
+ vaa.aa_chan = ch;
+ vaa.aa_iot = sc->sc_iot;
+ vaa.aa_memt = sc->sc_memt;
+ ch->ch_dev = config_found_ia(sc->sc_dev,
+ "hypervvmbus", &vaa, vmbus_attach_print);
+ }
+ break;
- SLIST_INIT(&sc->sc_icdevs);
- mutex_init(&sc->sc_icdev_lock, MUTEX_DEFAULT, IPL_NET);
+ case VMBUS_DEV_TYPE_DETACH:
+ ch = vd->vd_chan;
+ if (VMBUS_CHAN_ISPRIMARY(ch)) {
+ if (ch->ch_dev != NULL) {
+ config_detach(ch->ch_dev, DETACH_FORCE);
+ ch->ch_dev = NULL;
+ }
+ vmbus_channel_release(ch);
+ vmbus_channel_free(ch);
+ break;
+ }
- TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
- if (ch->ch_state != VMBUS_CHANSTATE_OFFERED)
- continue;
- if (ch->ch_flags & CHF_MONITOR)
- continue;
+ vmbus_channel_release(ch);
- dv = kmem_zalloc(sizeof(*dv), cold ? KM_NOSLEEP : KM_SLEEP);
- if (dv == NULL) {
- device_printf(sc->sc_dev,
- "failed to allocate ic device object\n");
- return ENOMEM;
+ prich = ch->ch_primary_channel;
+ mutex_enter(&prich->ch_subchannel_lock);
+ TAILQ_REMOVE(&prich->ch_subchannels, ch, ch_subentry);
+ prich->ch_subchannel_count--;
+ mutex_exit(&prich->ch_subchannel_lock);
+ wakeup(prich);
+
+ vmbus_channel_free(ch);
+ break;
+
+ default:
+ DPRINTF("%s: unknown offer type %d\n",
+ device_xname(sc->sc_dev), vd->vd_type);
+ break;
}
- dv->dv_aa.aa_type = &ch->ch_type;
- dv->dv_aa.aa_inst = &ch->ch_inst;
- dv->dv_aa.aa_ident = ch->ch_ident;
- dv->dv_aa.aa_chan = ch;
- dv->dv_aa.aa_iot = sc->sc_iot;
- dv->dv_aa.aa_memt = sc->sc_memt;
- mutex_enter(&sc->sc_icdev_lock);
- SLIST_INSERT_HEAD(&sc->sc_icdevs, dv, dv_entry);
- mutex_exit(&sc->sc_icdev_lock);
- ch->ch_dev = config_found_ia(sc->sc_dev, "hypervvmbus",
- &dv->dv_aa, vmbus_attach_print);
+ kmem_free(vd, sizeof(*vd));
+
+ mutex_enter(&sc->sc_devq_lock);
}
- return 0;
}
-static int
-vmbus_attach_devices(struct vmbus_softc *sc)
+static void
+vmbus_devq_thread(void *arg)
{
- struct vmbus_dev *dv;
- struct vmbus_channel *ch;
-
- SLIST_INIT(&sc->sc_devs);
- mutex_init(&sc->sc_dev_lock, MUTEX_DEFAULT, IPL_NET);
+ struct vmbus_softc *sc = arg;
- TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
- if (ch->ch_state != VMBUS_CHANSTATE_OFFERED)
- continue;
- if (!(ch->ch_flags & CHF_MONITOR))
+ mutex_enter(&sc->sc_devq_lock);
+ for (;;) {
+ if (SIMPLEQ_EMPTY(&sc->sc_devq)) {
+ cv_wait(&sc->sc_devq_cv, &sc->sc_devq_lock);
continue;
-
- dv = kmem_zalloc(sizeof(*dv), cold ? KM_NOSLEEP : KM_SLEEP);
- if (dv == NULL) {
- device_printf(sc->sc_dev,
- "failed to allocate device object\n");
- return ENOMEM;
}
- dv->dv_aa.aa_type = &ch->ch_type;
- dv->dv_aa.aa_inst = &ch->ch_inst;
- dv->dv_aa.aa_ident = ch->ch_ident;
- dv->dv_aa.aa_chan = ch;
- dv->dv_aa.aa_iot = sc->sc_iot;
- dv->dv_aa.aa_memt = sc->sc_memt;
- mutex_enter(&sc->sc_dev_lock);
- SLIST_INSERT_HEAD(&sc->sc_devs, dv, dv_entry);
- mutex_exit(&sc->sc_dev_lock);
- ch->ch_dev = config_found_ia(sc->sc_dev, "hypervvmbus",
- &dv->dv_aa, vmbus_attach_print);
+
+ vmbus_process_devq(sc);
}
- return 0;
+ mutex_exit(&sc->sc_devq_lock);
+
+ kthread_exit(0);
+}
+
+static int
+vmbus_attach_print(void *aux, const char *name)
+{
+ struct vmbus_attach_args *aa = aux;
+
+ if (name)
+ printf("\"%s\" at %s", aa->aa_ident, name);
+
+ return UNCONF;
}
MODULE(MODULE_CLASS_DRIVER, vmbus, "hyperv");
diff --git a/sys/dev/hyperv/vmbusvar.h b/sys/dev/hyperv/vmbusvar.h
index 63dee73bbf6..dc57a2baacf 100644
--- a/sys/dev/hyperv/vmbusvar.h
+++ b/sys/dev/hyperv/vmbusvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: vmbusvar.h,v 1.3 2019/12/07 11:45:45 nonaka Exp $ */
+/* $NetBSD: vmbusvar.h,v 1.4 2019/12/10 12:20:20 nonaka Exp $ */
/* $OpenBSD: hypervvar.h,v 1.13 2017/06/23 19:05:42 mikeb Exp $ */
/*
@@ -24,6 +24,7 @@
#include <sys/device.h>
#include <sys/atomic.h>
#include <sys/bus.h>
+#include <sys/condvar.h>
#include <sys/evcnt.h>
#include <sys/kcpuset.h>
#include <sys/mutex.h>
@@ -43,6 +44,7 @@
typedef void (*vmbus_channel_callback_t)(void *);
struct vmbus_softc;
+struct vmbus_channel;
struct vmbus_msg {
uint64_t msg_flags;
@@ -57,11 +59,14 @@ struct vmbus_msg {
__CTASSERT((offsetof(struct vmbus_msg, msg_req) % 8) == 0);
TAILQ_HEAD(vmbus_queue, vmbus_msg);
-struct vmbus_offer {
- struct vmbus_chanmsg_choffer co_chan;
- SIMPLEQ_ENTRY(vmbus_offer) co_entry;
+struct vmbus_dev {
+ int vd_type;
+#define VMBUS_DEV_TYPE_ATTACH 0
+#define VMBUS_DEV_TYPE_DETACH 1
+ struct vmbus_channel *vd_chan;
+ SIMPLEQ_ENTRY(vmbus_dev) vd_entry;
};
-SIMPLEQ_HEAD(vmbus_offers, vmbus_offer);
+SIMPLEQ_HEAD(vmbus_devq, vmbus_dev);
struct vmbus_ring_data {
struct vmbus_bufring *rd_ring;
@@ -72,7 +77,6 @@ struct vmbus_ring_data {
uint32_t rd_dsize;
};
-struct vmbus_channel;
TAILQ_HEAD(vmbus_channels, vmbus_channel);
struct vmbus_channel {
@@ -111,6 +115,7 @@ struct vmbus_channel {
uint32_t ch_flags;
#define CHF_BATCHED __BIT(0)
#define CHF_MONITOR __BIT(1)
+#define CHF_REVOKED __BIT(2)
uint8_t ch_mgroup;
uint8_t ch_mindex;
@@ -137,12 +142,6 @@ struct vmbus_attach_args {
bus_space_tag_t aa_memt;
};
-struct vmbus_dev {
- struct vmbus_attach_args dv_aa;
- SLIST_ENTRY(vmbus_dev) dv_entry;
-};
-SLIST_HEAD(vmbus_devices, vmbus_dev);
-
struct vmbus_percpu_data {
void *simp; /* Synthetic Interrupt Message Page */
void *siep; /* Synthetic Interrupt Event Flags Page */
@@ -190,19 +189,14 @@ struct vmbus_softc {
struct vmbus_queue sc_rsps; /* Response queue */
kmutex_t sc_rsp_lock;
- struct vmbus_offers sc_offers;
- kmutex_t sc_offer_lock;
+ struct vmbus_devq sc_devq;
+ kmutex_t sc_devq_lock;
+ kcondvar_t sc_devq_cv;
struct vmbus_channels sc_channels;
kmutex_t sc_channel_lock;
volatile uint32_t sc_handle;
-
- struct vmbus_devices sc_icdevs;
- kmutex_t sc_icdev_lock;
-
- struct vmbus_devices sc_devs;
- kmutex_t sc_dev_lock;
};
static __inline void
@@ -268,6 +262,7 @@ int vmbus_channel_recv(struct vmbus_channel *, void *, uint32_t, uint32_t *,
uint64_t *, int);
void vmbus_channel_cpu_set(struct vmbus_channel *, int);
void vmbus_channel_cpu_rr(struct vmbus_channel *);
+bool vmbus_channel_is_revoked(struct vmbus_channel *);
struct vmbus_channel **
vmbus_subchannel_get(struct vmbus_channel *, int);