Improve Hyper-V support.
vmbus(4): - Added support for multichannel. hvn(4): - Added support for multichannel. - Added support for change MTU. - Added support for TX aggregation. - Improve VLAN support. - Improve checksum offload support.
This commit is contained in:
parent
b97019535c
commit
fdd3eadbf8
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: hyperv.c,v 1.14 2021/12/23 04:06:51 yamaguchi Exp $ */
|
||||
/* $NetBSD: hyperv.c,v 1.15 2022/05/20 13:55:16 nonaka Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
|
||||
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#include <sys/cdefs.h>
|
||||
#ifdef __KERNEL_RCSID
|
||||
__KERNEL_RCSID(0, "$NetBSD: hyperv.c,v 1.14 2021/12/23 04:06:51 yamaguchi Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hyperv.c,v 1.15 2022/05/20 13:55:16 nonaka Exp $");
|
||||
#endif
|
||||
#ifdef __FBSDID
|
||||
__FBSDID("$FreeBSD: head/sys/dev/hyperv/vmbus/hyperv.c 331757 2018-03-30 02:25:12Z emaste $");
|
||||
|
@ -106,8 +106,6 @@ static char hyperv_hypercall_page[PAGE_SIZE]
|
|||
|
||||
static u_int hyperv_get_timecount(struct timecounter *);
|
||||
|
||||
static u_int hyperv_ver_major;
|
||||
|
||||
static u_int hyperv_features; /* CPUID_HV_MSR_ */
|
||||
static u_int hyperv_recommends;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.hyperv,v 1.2 2019/05/24 14:28:48 nonaka Exp $
|
||||
# $NetBSD: files.hyperv,v 1.3 2022/05/20 13:55:17 nonaka Exp $
|
||||
|
||||
define hypervvmbus {}
|
||||
device vmbus: hypervvmbus
|
||||
|
@ -14,6 +14,11 @@ file dev/hyperv/hvkbd.c hvkbd needs-flag
|
|||
device hvn: ether, ifnet, arp
|
||||
attach hvn at hypervvmbus
|
||||
file dev/hyperv/if_hvn.c hvn
|
||||
defparam opt_if_hvn.h HVN_UDP_CKSUM_FIXUP_MTU_DEFAULT
|
||||
HVN_CHANNEL_MAX_COUNT_DEFAULT
|
||||
HVN_CHANNEL_COUNT_DEFAULT
|
||||
HVN_TX_RING_COUNT_DEFAULT
|
||||
HVN_LINK_STATE_CHANGE_DELAY
|
||||
|
||||
device hvs: scsi
|
||||
attach hvs at hypervvmbus
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: hyperv_common.c,v 1.5 2019/12/10 12:20:20 nonaka Exp $ */
|
||||
/* $NetBSD: hyperv_common.c,v 1.6 2022/05/20 13:55:17 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.5 2019/12/10 12:20:20 nonaka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hyperv_common.c,v 1.6 2022/05/20 13:55:17 nonaka Exp $");
|
||||
|
||||
#include "hyperv.h"
|
||||
|
||||
|
@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: hyperv_common.c,v 1.5 2019/12/10 12:20:20 nonaka Exp
|
|||
#include <dev/hyperv/hypervreg.h>
|
||||
#include <dev/hyperv/hypervvar.h>
|
||||
|
||||
u_int hyperv_ver_major;
|
||||
hyperv_tc64_t hyperv_tc64;
|
||||
|
||||
int hyperv_nullop(void);
|
||||
|
@ -111,46 +112,40 @@ 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, int flags)
|
||||
bus_size_t alignment, bus_size_t boundary, int nsegs)
|
||||
{
|
||||
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_intr_zalloc(sizeof(*dma->segs) * nsegs, kmemflags);
|
||||
if (dma->segs == NULL)
|
||||
return NULL;
|
||||
|
||||
dma->segs = kmem_zalloc(sizeof(*dma->segs) * nsegs, KM_SLEEP);
|
||||
dma->nsegs = nsegs;
|
||||
|
||||
error = bus_dmamem_alloc(dmat, size, alignment, boundary, dma->segs,
|
||||
nsegs, &rseg, dmaflags);
|
||||
nsegs, &rseg, BUS_DMA_WAITOK);
|
||||
if (error) {
|
||||
printf("%s: bus_dmamem_alloc failed: error=%d\n",
|
||||
__func__, error);
|
||||
goto fail1;
|
||||
}
|
||||
error = bus_dmamem_map(dmat, dma->segs, rseg, size, &dma->addr,
|
||||
dmaflags);
|
||||
BUS_DMA_WAITOK);
|
||||
if (error) {
|
||||
printf("%s: bus_dmamem_map failed: error=%d\n",
|
||||
__func__, error);
|
||||
goto fail2;
|
||||
}
|
||||
error = bus_dmamap_create(dmat, size, rseg, size, boundary, dmaflags,
|
||||
&dma->map);
|
||||
error = bus_dmamap_create(dmat, size, rseg, size, boundary,
|
||||
BUS_DMA_WAITOK, &dma->map);
|
||||
if (error) {
|
||||
printf("%s: bus_dmamap_create failed: error=%d\n",
|
||||
__func__, error);
|
||||
goto fail3;
|
||||
}
|
||||
error = bus_dmamap_load(dmat, dma->map, dma->addr, size, NULL,
|
||||
BUS_DMA_READ | BUS_DMA_WRITE | dmaflags);
|
||||
BUS_DMA_READ | BUS_DMA_WRITE | BUS_DMA_WAITOK);
|
||||
if (error) {
|
||||
printf("%s: bus_dmamap_load failed: error=%d\n",
|
||||
__func__, error);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: hypervreg.h,v 1.1 2019/02/15 08:54:01 nonaka Exp $ */
|
||||
/* $NetBSD: hypervreg.h,v 1.2 2022/05/20 13:55:17 nonaka Exp $ */
|
||||
/* $OpenBSD: hypervreg.h,v 1.10 2017/01/05 13:17:22 mikeb Exp $ */
|
||||
|
||||
/*-
|
||||
|
@ -258,6 +258,7 @@ struct vmbus_bufring {
|
|||
uint8_t br_rsvd[4084];
|
||||
uint8_t br_data[0];
|
||||
} __packed;
|
||||
__CTASSERT(sizeof(struct vmbus_bufring) == PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Channel
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: hypervvar.h,v 1.5 2021/12/23 04:06:51 yamaguchi Exp $ */
|
||||
/* $NetBSD: hypervvar.h,v 1.6 2022/05/20 13:55:17 nonaka Exp $ */
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
|
@ -59,6 +59,7 @@ __CTASSERT(sizeof(struct hyperv_reftsc) == PAGE_SIZE);
|
|||
#endif
|
||||
|
||||
#if defined(_KERNEL)
|
||||
extern u_int hyperv_ver_major;
|
||||
|
||||
int hyperv_hypercall_enabled(void);
|
||||
int hyperv_synic_supported(void);
|
||||
|
@ -108,10 +109,8 @@ 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, int);
|
||||
bus_size_t, bus_size_t, int);
|
||||
void hyperv_dma_free(bus_dma_tag_t, struct hyperv_dma *);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_hvnreg.h,v 1.2 2021/10/21 13:21:54 andvar Exp $ */
|
||||
/* $NetBSD: if_hvnreg.h,v 1.3 2022/05/20 13:55:17 nonaka Exp $ */
|
||||
/* $OpenBSD: if_hvnreg.h,v 1.3 2016/09/14 17:48:28 mikeb Exp $ */
|
||||
|
||||
/*-
|
||||
|
@ -201,4 +201,21 @@ struct hvn_nvs_rndis_ack {
|
|||
uint8_t nvs_rsvd[24];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* RNDIS extension
|
||||
*/
|
||||
|
||||
/* Per-packet hash info */
|
||||
#define HVN_NDIS_HASH_INFO_SIZE sizeof(uint32_t)
|
||||
#define HVN_NDIS_PKTINFO_TYPE_HASHINF NDIS_PKTINFO_TYPE_ORIG_NBLIST
|
||||
/* NDIS_HASH_ */
|
||||
|
||||
/* Per-packet hash value */
|
||||
#define HVN_NDIS_HASH_VALUE_SIZE sizeof(uint32_t)
|
||||
#define HVN_NDIS_PKTINFO_TYPE_HASHVAL NDIS_PKTINFO_TYPE_PKT_CANCELID
|
||||
|
||||
/* Per-packet-info size */
|
||||
#define HVN_RNDIS_PKTINFO_SIZE(dlen) \
|
||||
offsetof(struct rndis_pktinfo, rm_data[dlen])
|
||||
|
||||
#endif /* _IF_HVNREG_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vmbus.c,v 1.17 2022/04/09 23:38:32 riastradh Exp $ */
|
||||
/* $NetBSD: vmbus.c,v 1.18 2022/05/20 13:55:17 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.17 2022/04/09 23:38:32 riastradh Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.18 2022/05/20 13:55:17 nonaka Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -100,9 +100,6 @@ static struct vmbus_channel *
|
|||
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 void vmbus_chevq_enqueue(struct vmbus_softc *, int, void *);
|
||||
static void vmbus_process_chevq(void *);
|
||||
static void vmbus_chevq_thread(void *);
|
||||
|
@ -274,6 +271,9 @@ vmbus_attach(struct vmbus_softc *sc)
|
|||
"hvmsg", NULL, IPL_NET, NULL, NULL, NULL);
|
||||
hyperv_set_message_proc(vmbus_message_proc, sc);
|
||||
|
||||
sc->sc_chanmap = kmem_zalloc(sizeof(struct vmbus_channel *) *
|
||||
VMBUS_CHAN_MAX, KM_SLEEP);
|
||||
|
||||
if (vmbus_alloc_dma(sc))
|
||||
goto cleanup;
|
||||
|
||||
|
@ -306,6 +306,8 @@ vmbus_attach(struct vmbus_softc *sc)
|
|||
cleanup:
|
||||
vmbus_deinit_interrupts(sc);
|
||||
vmbus_free_dma(sc);
|
||||
kmem_free(__UNVOLATILE(sc->sc_chanmap),
|
||||
sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -326,6 +328,8 @@ vmbus_detach(struct vmbus_softc *sc, int flags)
|
|||
|
||||
vmbus_deinit_interrupts(sc);
|
||||
vmbus_free_dma(sc);
|
||||
kmem_free(__UNVOLATILE(sc->sc_chanmap),
|
||||
sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -345,18 +349,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, HYPERV_DMA_SLEEPOK);
|
||||
PAGE_SIZE, PAGE_SIZE, 0, 1);
|
||||
if (pd->simp == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
pd->siep = hyperv_dma_alloc(sc->sc_dmat, &pd->siep_dma,
|
||||
PAGE_SIZE, PAGE_SIZE, 0, 1, HYPERV_DMA_SLEEPOK);
|
||||
PAGE_SIZE, PAGE_SIZE, 0, 1);
|
||||
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, HYPERV_DMA_SLEEPOK);
|
||||
PAGE_SIZE, PAGE_SIZE, 0, 1);
|
||||
if (sc->sc_events == NULL)
|
||||
return ENOMEM;
|
||||
sc->sc_wevents = (u_long *)sc->sc_events;
|
||||
|
@ -364,8 +368,7 @@ 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,
|
||||
HYPERV_DMA_SLEEPOK);
|
||||
&sc->sc_monitor_dma[i], PAGE_SIZE, PAGE_SIZE, 0, 1);
|
||||
if (sc->sc_monitor[i] == NULL)
|
||||
return ENOMEM;
|
||||
}
|
||||
|
@ -523,7 +526,7 @@ vmbus_connect(struct vmbus_softc *sc)
|
|||
for (i = 0; i < __arraycount(versions); i++) {
|
||||
cmd.chm_ver = versions[i];
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp),
|
||||
cold ? HCF_NOSLEEP : HCF_SLEEPOK);
|
||||
HCF_NOSLEEP);
|
||||
if (rv) {
|
||||
DPRINTF("%s: CONNECT failed\n",
|
||||
device_xname(sc->sc_dev));
|
||||
|
@ -549,7 +552,6 @@ static int
|
|||
vmbus_cmd(struct vmbus_softc *sc, void *cmd, size_t cmdlen, void *rsp,
|
||||
size_t rsplen, int flags)
|
||||
{
|
||||
const int prflags = cold ? PR_NOWAIT : PR_WAITOK;
|
||||
struct vmbus_msg *msg;
|
||||
paddr_t pa;
|
||||
int rv;
|
||||
|
@ -560,7 +562,7 @@ vmbus_cmd(struct vmbus_softc *sc, void *cmd, size_t cmdlen, void *rsp,
|
|||
return EMSGSIZE;
|
||||
}
|
||||
|
||||
msg = pool_cache_get_paddr(sc->sc_msgpool, prflags, &pa);
|
||||
msg = pool_cache_get_paddr(sc->sc_msgpool, PR_WAITOK, &pa);
|
||||
if (msg == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't get msgpool\n");
|
||||
return ENOMEM;
|
||||
|
@ -588,11 +590,9 @@ vmbus_cmd(struct vmbus_softc *sc, void *cmd, size_t cmdlen, void *rsp,
|
|||
static int
|
||||
vmbus_start(struct vmbus_softc *sc, struct vmbus_msg *msg, paddr_t msg_pa)
|
||||
{
|
||||
static const int delays[] = {
|
||||
100, 100, 100, 500, 500, 5000, 5000, 5000
|
||||
};
|
||||
const char *wchan = "hvstart";
|
||||
uint16_t status;
|
||||
int wait_ms = 1; /* milliseconds */
|
||||
int i, s;
|
||||
|
||||
msg->msg_req.hc_connid = VMBUS_CONNID_MESSAGE;
|
||||
|
@ -604,33 +604,45 @@ vmbus_start(struct vmbus_softc *sc, struct vmbus_msg *msg, paddr_t msg_pa)
|
|||
mutex_exit(&sc->sc_req_lock);
|
||||
}
|
||||
|
||||
for (i = 0; i < __arraycount(delays); i++) {
|
||||
/*
|
||||
* In order to cope with transient failures, e.g. insufficient
|
||||
* resources on host side, we retry the post message Hypercall
|
||||
* several times. 20 retries seem sufficient.
|
||||
*/
|
||||
#define HC_RETRY_MAX 20
|
||||
#define HC_WAIT_MAX (2 * 1000) /* 2s */
|
||||
|
||||
for (i = 0; i < HC_RETRY_MAX; i++) {
|
||||
status = hyperv_hypercall_post_message(
|
||||
msg_pa + offsetof(struct vmbus_msg, msg_req));
|
||||
if (status == HYPERCALL_STATUS_SUCCESS)
|
||||
break;
|
||||
return 0;
|
||||
|
||||
if (msg->msg_flags & MSGF_NOSLEEP) {
|
||||
delay(delays[i]);
|
||||
DELAY(wait_ms * 1000);
|
||||
s = splnet();
|
||||
hyperv_intr();
|
||||
splx(s);
|
||||
} else
|
||||
tsleep(wchan, PRIBIO, wchan,
|
||||
uimax(1, mstohz(delays[i] / 1000)));
|
||||
}
|
||||
if (status != HYPERCALL_STATUS_SUCCESS) {
|
||||
device_printf(sc->sc_dev,
|
||||
"posting vmbus message failed with %d\n", status);
|
||||
if (!(msg->msg_flags & MSGF_NOQUEUE)) {
|
||||
mutex_enter(&sc->sc_req_lock);
|
||||
TAILQ_REMOVE(&sc->sc_reqs, msg, msg_entry);
|
||||
mutex_exit(&sc->sc_req_lock);
|
||||
}
|
||||
return EIO;
|
||||
tsleep(wchan, PRIBIO, wchan, uimax(1, mstohz(wait_ms)));
|
||||
|
||||
if (wait_ms < HC_WAIT_MAX)
|
||||
wait_ms *= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#undef HC_RETRY_MAX
|
||||
#undef HC_WAIT_MAX
|
||||
|
||||
device_printf(sc->sc_dev,
|
||||
"posting vmbus message failed with %d\n", status);
|
||||
|
||||
if (!(msg->msg_flags & MSGF_NOQUEUE)) {
|
||||
mutex_enter(&sc->sc_req_lock);
|
||||
TAILQ_REMOVE(&sc->sc_reqs, msg, msg_entry);
|
||||
mutex_exit(&sc->sc_req_lock);
|
||||
}
|
||||
|
||||
return EIO;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -664,7 +676,7 @@ vmbus_reply(struct vmbus_softc *sc, struct vmbus_msg *msg)
|
|||
hyperv_intr();
|
||||
splx(s);
|
||||
} else
|
||||
tsleep(msg, PRIBIO, "hvreply", 1);
|
||||
tsleep(msg, PRIBIO, "hvreply", uimax(1, mstohz(1)));
|
||||
}
|
||||
|
||||
mutex_enter(&sc->sc_rsp_lock);
|
||||
|
@ -705,7 +717,8 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *revents,
|
|||
continue;
|
||||
|
||||
pending = atomic_swap_ulong(&revents[row], 0);
|
||||
chanid_base = row * LONG_BIT;
|
||||
pending &= ~sc->sc_evtmask[row];
|
||||
chanid_base = row * VMBUS_EVTFLAG_LEN;
|
||||
|
||||
while ((chanid_ofs = ffsl(pending)) != 0) {
|
||||
chanid_ofs--; /* NOTE: ffs is 1-based */
|
||||
|
@ -716,12 +729,12 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *revents,
|
|||
if (chanid == 0)
|
||||
continue;
|
||||
|
||||
ch = vmbus_channel_lookup(sc, chanid);
|
||||
if (ch == NULL) {
|
||||
device_printf(sc->sc_dev,
|
||||
"unhandled event on %d\n", chanid);
|
||||
ch = sc->sc_chanmap[chanid];
|
||||
if (__predict_false(ch == NULL)) {
|
||||
/* Channel is closed. */
|
||||
continue;
|
||||
}
|
||||
__insn_barrier();
|
||||
if (ch->ch_state != VMBUS_CHANSTATE_OPENED) {
|
||||
device_printf(sc->sc_dev,
|
||||
"channel %d is not active\n", chanid);
|
||||
|
@ -987,7 +1000,7 @@ vmbus_channel_scan(struct vmbus_softc *sc)
|
|||
hdr.chm_type = VMBUS_CHANMSG_CHREQUEST;
|
||||
|
||||
if (vmbus_cmd(sc, &hdr, sizeof(hdr), &rsp, sizeof(rsp),
|
||||
HCF_NOREPLY | (cold ? HCF_NOSLEEP : HCF_SLEEPOK))) {
|
||||
HCF_NOREPLY | HCF_NOSLEEP)) {
|
||||
DPRINTF("%s: CHREQUEST failed\n", device_xname(sc->sc_dev));
|
||||
return -1;
|
||||
}
|
||||
|
@ -1013,7 +1026,7 @@ vmbus_channel_alloc(struct vmbus_softc *sc)
|
|||
ch = kmem_zalloc(sizeof(*ch), KM_SLEEP);
|
||||
|
||||
ch->ch_monprm = hyperv_dma_alloc(sc->sc_dmat, &ch->ch_monprm_dma,
|
||||
sizeof(*ch->ch_monprm), 8, 0, 1, HYPERV_DMA_SLEEPOK);
|
||||
sizeof(*ch->ch_monprm), 8, 0, 1);
|
||||
if (ch->ch_monprm == NULL) {
|
||||
device_printf(sc->sc_dev, "monprm alloc failed\n");
|
||||
kmem_free(ch, sizeof(*ch));
|
||||
|
@ -1022,7 +1035,10 @@ vmbus_channel_alloc(struct vmbus_softc *sc)
|
|||
|
||||
ch->ch_refs = 1;
|
||||
ch->ch_sc = sc;
|
||||
mutex_init(&ch->ch_event_lock, MUTEX_DEFAULT, IPL_NET);
|
||||
cv_init(&ch->ch_event_cv, "hvevwait");
|
||||
mutex_init(&ch->ch_subchannel_lock, MUTEX_DEFAULT, IPL_NET);
|
||||
cv_init(&ch->ch_subchannel_cv, "hvsubch");
|
||||
TAILQ_INIT(&ch->ch_subchannels);
|
||||
|
||||
ch->ch_state = VMBUS_CHANSTATE_CLOSED;
|
||||
|
@ -1043,7 +1059,10 @@ vmbus_channel_free(struct vmbus_channel *ch)
|
|||
ch->ch_id, ch->ch_refs);
|
||||
|
||||
hyperv_dma_free(sc->sc_dmat, &ch->ch_monprm_dma);
|
||||
mutex_destroy(&ch->ch_event_lock);
|
||||
cv_destroy(&ch->ch_event_cv);
|
||||
mutex_destroy(&ch->ch_subchannel_lock);
|
||||
cv_destroy(&ch->ch_subchannel_cv);
|
||||
/* XXX ch_evcnt */
|
||||
if (ch->ch_taskq != NULL)
|
||||
softint_disestablish(ch->ch_taskq);
|
||||
|
@ -1055,7 +1074,7 @@ vmbus_channel_add(struct vmbus_channel *nch)
|
|||
{
|
||||
struct vmbus_softc *sc = nch->ch_sc;
|
||||
struct vmbus_channel *ch;
|
||||
u_int refs __diagused;
|
||||
int refs __diagused;
|
||||
|
||||
if (nch->ch_id == 0) {
|
||||
device_printf(sc->sc_dev, "got channel 0 offer, discard\n");
|
||||
|
@ -1105,8 +1124,8 @@ vmbus_channel_add(struct vmbus_channel *nch)
|
|||
mutex_enter(&ch->ch_subchannel_lock);
|
||||
TAILQ_INSERT_TAIL(&ch->ch_subchannels, nch, ch_subentry);
|
||||
ch->ch_subchannel_count++;
|
||||
cv_signal(&ch->ch_subchannel_cv);
|
||||
mutex_exit(&ch->ch_subchannel_lock);
|
||||
wakeup(ch);
|
||||
|
||||
done:
|
||||
mutex_enter(&sc->sc_channel_lock);
|
||||
|
@ -1133,6 +1152,10 @@ vmbus_channel_cpu_set(struct vmbus_channel *ch, int cpu)
|
|||
|
||||
ch->ch_cpuid = cpu;
|
||||
ch->ch_vcpu = hyperv_get_vcpuid(cpu);
|
||||
|
||||
aprint_debug_dev(ch->ch_dev != NULL ? ch->ch_dev : sc->sc_dev,
|
||||
"channel %u assigned to cpu%u [vcpu%u]\n",
|
||||
ch->ch_id, ch->ch_cpuid, ch->ch_vcpu);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1270,7 +1293,7 @@ vmbus_channel_release(struct vmbus_channel *ch)
|
|||
cmd.chm_chanid = ch->ch_id;
|
||||
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), NULL, 0,
|
||||
HCF_NOREPLY | (cold ? HCF_NOSLEEP : HCF_SLEEPOK));
|
||||
HCF_NOREPLY | HCF_SLEEPOK);
|
||||
if (rv) {
|
||||
DPRINTF("%s: CHFREE failed with %d\n", device_xname(sc->sc_dev),
|
||||
rv);
|
||||
|
@ -1279,19 +1302,21 @@ vmbus_channel_release(struct vmbus_channel *ch)
|
|||
}
|
||||
|
||||
struct vmbus_channel **
|
||||
vmbus_subchannel_get(struct vmbus_channel *prich, int cnt)
|
||||
vmbus_subchannel_get(struct vmbus_channel *prich, int subchan_cnt)
|
||||
{
|
||||
struct vmbus_softc *sc = prich->ch_sc;
|
||||
struct vmbus_channel **ret, *ch;
|
||||
int i, s;
|
||||
|
||||
KASSERTMSG(cnt > 0, "invalid sub-channel count %d", cnt);
|
||||
KASSERTMSG(subchan_cnt > 0,
|
||||
"invalid sub-channel count %d", subchan_cnt);
|
||||
|
||||
ret = kmem_zalloc(sizeof(struct vmbus_channel *) * cnt, KM_SLEEP);
|
||||
ret = kmem_zalloc(sizeof(struct vmbus_channel *) * subchan_cnt,
|
||||
KM_SLEEP);
|
||||
|
||||
mutex_enter(&prich->ch_subchannel_lock);
|
||||
|
||||
while (prich->ch_subchannel_count < cnt) {
|
||||
while (prich->ch_subchannel_count < subchan_cnt) {
|
||||
if (cold) {
|
||||
mutex_exit(&prich->ch_subchannel_lock);
|
||||
delay(1000);
|
||||
|
@ -1312,12 +1337,12 @@ vmbus_subchannel_get(struct vmbus_channel *prich, int cnt)
|
|||
TAILQ_FOREACH(ch, &prich->ch_subchannels, ch_subentry) {
|
||||
ret[i] = ch; /* XXX inc refs */
|
||||
|
||||
if (++i == cnt)
|
||||
if (++i == subchan_cnt)
|
||||
break;
|
||||
}
|
||||
|
||||
KASSERTMSG(i == cnt, "invalid subchan count %d, should be %d",
|
||||
prich->ch_subchannel_count, cnt);
|
||||
KASSERTMSG(i == subchan_cnt, "invalid subchan count %d, should be %d",
|
||||
prich->ch_subchannel_count, subchan_cnt);
|
||||
|
||||
mutex_exit(&prich->ch_subchannel_lock);
|
||||
|
||||
|
@ -1325,19 +1350,41 @@ vmbus_subchannel_get(struct vmbus_channel *prich, int cnt)
|
|||
}
|
||||
|
||||
void
|
||||
vmbus_subchannel_put(struct vmbus_channel **subch, int cnt)
|
||||
vmbus_subchannel_rel(struct vmbus_channel **subch, int cnt)
|
||||
{
|
||||
|
||||
kmem_free(subch, sizeof(struct vmbus_channel *) * cnt);
|
||||
}
|
||||
|
||||
static struct vmbus_channel *
|
||||
vmbus_channel_lookup(struct vmbus_softc *sc, uint32_t relid)
|
||||
void
|
||||
vmbus_subchannel_drain(struct vmbus_channel *prich)
|
||||
{
|
||||
struct vmbus_channel *ch;
|
||||
int s;
|
||||
|
||||
mutex_enter(&prich->ch_subchannel_lock);
|
||||
while (prich->ch_subchannel_count > 0) {
|
||||
if (cold) {
|
||||
mutex_exit(&prich->ch_subchannel_lock);
|
||||
delay(1000);
|
||||
s = splnet();
|
||||
hyperv_intr();
|
||||
splx(s);
|
||||
mutex_enter(&prich->ch_subchannel_lock);
|
||||
} else {
|
||||
cv_wait(&prich->ch_subchannel_cv,
|
||||
&prich->ch_subchannel_lock);
|
||||
}
|
||||
}
|
||||
mutex_exit(&prich->ch_subchannel_lock);
|
||||
}
|
||||
|
||||
static struct vmbus_channel *
|
||||
vmbus_channel_lookup(struct vmbus_softc *sc, uint32_t chanid)
|
||||
{
|
||||
struct vmbus_channel *ch = NULL;
|
||||
|
||||
TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
|
||||
if (ch->ch_id == relid)
|
||||
if (ch->ch_id == chanid)
|
||||
return ch;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1352,7 +1399,7 @@ vmbus_channel_ring_create(struct vmbus_channel *ch, uint32_t buflen)
|
|||
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, HYPERV_DMA_SLEEPOK);
|
||||
ch->ch_ring_size, PAGE_SIZE, 0, 1);
|
||||
if (ch->ch_ring == NULL) {
|
||||
device_printf(sc->sc_dev,
|
||||
"failed to allocate channel ring\n");
|
||||
|
@ -1414,6 +1461,9 @@ vmbus_channel_open(struct vmbus_channel *ch, size_t buflen, void *udata,
|
|||
return rv;
|
||||
}
|
||||
|
||||
__insn_barrier();
|
||||
sc->sc_chanmap[ch->ch_id] = ch;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.chm_hdr.chm_type = VMBUS_CHANMSG_CHOPEN;
|
||||
cmd.chm_openid = ch->ch_id;
|
||||
|
@ -1430,9 +1480,9 @@ vmbus_channel_open(struct vmbus_channel *ch, size_t buflen, void *udata,
|
|||
ch->ch_ctx = arg;
|
||||
ch->ch_state = VMBUS_CHANSTATE_OPENED;
|
||||
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp),
|
||||
cold ? HCF_NOSLEEP : HCF_SLEEPOK);
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp), HCF_NOSLEEP);
|
||||
if (rv) {
|
||||
sc->sc_chanmap[ch->ch_id] = NULL;
|
||||
vmbus_channel_ring_destroy(ch);
|
||||
DPRINTF("%s: CHOPEN failed with %d\n", device_xname(sc->sc_dev),
|
||||
rv);
|
||||
|
@ -1468,13 +1518,15 @@ vmbus_channel_close_internal(struct vmbus_channel *ch)
|
|||
struct vmbus_chanmsg_chclose cmd;
|
||||
int rv;
|
||||
|
||||
sc->sc_chanmap[ch->ch_id] = NULL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.chm_hdr.chm_type = VMBUS_CHANMSG_CHCLOSE;
|
||||
cmd.chm_chanid = ch->ch_id;
|
||||
|
||||
ch->ch_state = VMBUS_CHANSTATE_CLOSING;
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), NULL, 0,
|
||||
HCF_NOREPLY | (cold ? HCF_NOSLEEP : HCF_SLEEPOK));
|
||||
HCF_NOREPLY | HCF_NOSLEEP);
|
||||
if (rv) {
|
||||
DPRINTF("%s: CHCLOSE failed with %d\n",
|
||||
device_xname(sc->sc_dev), rv);
|
||||
|
@ -1513,7 +1565,7 @@ vmbus_channel_close(struct vmbus_channel *ch)
|
|||
(void) rv; /* XXX */
|
||||
vmbus_channel_detach(ch);
|
||||
}
|
||||
vmbus_subchannel_put(subch, cnt);
|
||||
vmbus_subchannel_rel(subch, cnt);
|
||||
}
|
||||
|
||||
return vmbus_channel_close_internal(ch);
|
||||
|
@ -1618,6 +1670,13 @@ vmbus_ring_avail(struct vmbus_ring_data *rd, uint32_t *towrite,
|
|||
*toread = r;
|
||||
}
|
||||
|
||||
static bool
|
||||
vmbus_ring_is_empty(struct vmbus_ring_data *rd)
|
||||
{
|
||||
|
||||
return rd->rd_ring->br_rindex == rd->rd_ring->br_windex;
|
||||
}
|
||||
|
||||
static int
|
||||
vmbus_ring_write(struct vmbus_ring_data *wrd, struct iovec *iov, int iov_cnt,
|
||||
int *needsig)
|
||||
|
@ -1886,25 +1945,29 @@ vmbus_ring_unmask(struct vmbus_ring_data *rd)
|
|||
membar_sync();
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
vmbus_channel_pause(struct vmbus_channel *ch)
|
||||
{
|
||||
|
||||
atomic_or_ulong(&ch->ch_sc->sc_evtmask[ch->ch_id / VMBUS_EVTFLAG_LEN],
|
||||
__BIT(ch->ch_id % VMBUS_EVTFLAG_LEN));
|
||||
vmbus_ring_mask(&ch->ch_rrd);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
uint32_t
|
||||
vmbus_channel_unpause(struct vmbus_channel *ch)
|
||||
{
|
||||
uint32_t avail;
|
||||
|
||||
atomic_and_ulong(&ch->ch_sc->sc_evtmask[ch->ch_id / VMBUS_EVTFLAG_LEN],
|
||||
~__BIT(ch->ch_id % VMBUS_EVTFLAG_LEN));
|
||||
vmbus_ring_unmask(&ch->ch_rrd);
|
||||
vmbus_ring_avail(&ch->ch_rrd, NULL, &avail);
|
||||
|
||||
return avail;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
uint32_t
|
||||
vmbus_channel_ready(struct vmbus_channel *ch)
|
||||
{
|
||||
uint32_t avail;
|
||||
|
@ -1914,6 +1977,20 @@ vmbus_channel_ready(struct vmbus_channel *ch)
|
|||
return avail;
|
||||
}
|
||||
|
||||
bool
|
||||
vmbus_channel_tx_empty(struct vmbus_channel *ch)
|
||||
{
|
||||
|
||||
return vmbus_ring_is_empty(&ch->ch_wrd);
|
||||
}
|
||||
|
||||
bool
|
||||
vmbus_channel_rx_empty(struct vmbus_channel *ch)
|
||||
{
|
||||
|
||||
return vmbus_ring_is_empty(&ch->ch_rrd);
|
||||
}
|
||||
|
||||
/* How many PFNs can be referenced by the header */
|
||||
#define VMBUS_NPFNHDR ((VMBUS_MSG_DSIZE_MAX - \
|
||||
sizeof(struct vmbus_chanmsg_gpadl_conn)) / sizeof(uint64_t))
|
||||
|
@ -1926,10 +2003,6 @@ int
|
|||
vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
|
||||
uint32_t buflen, uint32_t *handle)
|
||||
{
|
||||
const int prflags = cold ? PR_NOWAIT : PR_WAITOK;
|
||||
const int kmemflags = cold ? KM_NOSLEEP : KM_SLEEP;
|
||||
const int msgflags = cold ? MSGF_NOSLEEP : 0;
|
||||
const int hcflags = cold ? HCF_NOSLEEP : HCF_SLEEPOK;
|
||||
struct vmbus_softc *sc = ch->ch_sc;
|
||||
struct vmbus_chanmsg_gpadl_conn *hdr;
|
||||
struct vmbus_chanmsg_gpadl_subconn *cmd;
|
||||
|
@ -1948,16 +2021,10 @@ vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
|
|||
KASSERT((buflen & PAGE_MASK) == 0);
|
||||
KASSERT(buflen == (uint32_t)dma->map->dm_mapsize);
|
||||
|
||||
msg = pool_cache_get_paddr(sc->sc_msgpool, prflags, &pa);
|
||||
if (msg == NULL)
|
||||
return ENOMEM;
|
||||
msg = pool_cache_get_paddr(sc->sc_msgpool, PR_WAITOK, &pa);
|
||||
|
||||
/* Prepare array of frame addresses */
|
||||
frames = kmem_zalloc(total * sizeof(*frames), kmemflags);
|
||||
if (frames == NULL) {
|
||||
pool_cache_put_paddr(sc->sc_msgpool, msg, pa);
|
||||
return ENOMEM;
|
||||
}
|
||||
frames = kmem_zalloc(total * sizeof(*frames), KM_SLEEP);
|
||||
for (i = 0, j = 0; i < dma->map->dm_nsegs && j < total; i++) {
|
||||
bus_dma_segment_t *seg = &dma->map->dm_segs[i];
|
||||
bus_addr_t addr = seg->ds_addr;
|
||||
|
@ -1977,7 +2044,7 @@ vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
|
|||
hdr = (struct vmbus_chanmsg_gpadl_conn *)msg->msg_req.hc_data;
|
||||
msg->msg_rsp = &rsp;
|
||||
msg->msg_rsplen = sizeof(rsp);
|
||||
msg->msg_flags = msgflags;
|
||||
msg->msg_flags = MSGF_NOSLEEP;
|
||||
|
||||
left = total - inhdr;
|
||||
|
||||
|
@ -1985,12 +2052,7 @@ vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
|
|||
if (left > 0) {
|
||||
ncmds = howmany(left, VMBUS_NPFNBODY);
|
||||
bodylen = ncmds * VMBUS_MSG_DSIZE_MAX;
|
||||
body = kmem_zalloc(bodylen, kmemflags);
|
||||
if (body == NULL) {
|
||||
kmem_free(frames, total * sizeof(*frames));
|
||||
pool_cache_put_paddr(sc->sc_msgpool, msg, pa);
|
||||
return ENOMEM;
|
||||
}
|
||||
body = kmem_zalloc(bodylen, KM_SLEEP);
|
||||
}
|
||||
|
||||
*handle = atomic_inc_32_nv(&sc->sc_handle);
|
||||
|
@ -2035,7 +2097,8 @@ vmbus_handle_alloc(struct vmbus_channel *ch, const struct hyperv_dma *dma,
|
|||
cmdlen += last * sizeof(uint64_t);
|
||||
else
|
||||
cmdlen += VMBUS_NPFNBODY * sizeof(uint64_t);
|
||||
rv = vmbus_cmd(sc, cmd, cmdlen, NULL, 0, HCF_NOREPLY | hcflags);
|
||||
rv = vmbus_cmd(sc, cmd, cmdlen, NULL, 0,
|
||||
HCF_NOREPLY | HCF_NOSLEEP);
|
||||
if (rv != 0) {
|
||||
DPRINTF("%s: GPADL_SUBCONN (iteration %d/%d) failed "
|
||||
"with %d\n", device_xname(sc->sc_dev), i, ncmds,
|
||||
|
@ -2075,8 +2138,7 @@ vmbus_handle_free(struct vmbus_channel *ch, uint32_t handle)
|
|||
cmd.chm_chanid = ch->ch_id;
|
||||
cmd.chm_gpadl = handle;
|
||||
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp),
|
||||
cold ? HCF_NOSLEEP : HCF_SLEEPOK);
|
||||
rv = vmbus_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp), HCF_NOSLEEP);
|
||||
if (rv) {
|
||||
DPRINTF("%s: GPADL_DISCONN failed with %d\n",
|
||||
device_xname(sc->sc_dev), rv);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vmbusvar.h,v 1.6 2020/07/14 00:45:53 yamaguchi Exp $ */
|
||||
/* $NetBSD: vmbusvar.h,v 1.7 2022/05/20 13:55:17 nonaka Exp $ */
|
||||
/* $OpenBSD: hypervvar.h,v 1.13 2017/06/23 19:05:42 mikeb Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -121,6 +121,9 @@ struct vmbus_channel {
|
|||
struct evcnt ch_evcnt;
|
||||
void *ch_taskq;
|
||||
|
||||
kmutex_t ch_event_lock;
|
||||
kcondvar_t ch_event_cv;
|
||||
|
||||
uint32_t ch_flags;
|
||||
#define CHF_BATCHED __BIT(0)
|
||||
#define CHF_MONITOR __BIT(1)
|
||||
|
@ -135,6 +138,7 @@ struct vmbus_channel {
|
|||
TAILQ_ENTRY(vmbus_channel) ch_entry;
|
||||
|
||||
kmutex_t ch_subchannel_lock;
|
||||
kcondvar_t ch_subchannel_cv;
|
||||
struct vmbus_channels ch_subchannels;
|
||||
u_int ch_subchannel_count;
|
||||
TAILQ_ENTRY(vmbus_channel) ch_subentry;
|
||||
|
@ -175,6 +179,8 @@ struct vmbus_softc {
|
|||
|
||||
u_long *sc_wevents; /* Write events */
|
||||
u_long *sc_revents; /* Read events */
|
||||
struct vmbus_channel * volatile *sc_chanmap;
|
||||
volatile u_long sc_evtmask[VMBUS_EVTFLAGS_MAX];
|
||||
struct vmbus_mnf *sc_monitor[2];
|
||||
struct vmbus_percpu_data sc_percpu[MAXCPUS];
|
||||
|
||||
|
@ -286,9 +292,15 @@ int vmbus_channel_recv(struct vmbus_channel *, void *, uint32_t, uint32_t *,
|
|||
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 *);
|
||||
bool vmbus_channel_tx_empty(struct vmbus_channel *);
|
||||
bool vmbus_channel_rx_empty(struct vmbus_channel *);
|
||||
void vmbus_channel_pause(struct vmbus_channel *);
|
||||
uint32_t vmbus_channel_unpause(struct vmbus_channel *);
|
||||
uint32_t vmbus_channel_ready(struct vmbus_channel *);
|
||||
|
||||
struct vmbus_channel **
|
||||
vmbus_subchannel_get(struct vmbus_channel *, int);
|
||||
void vmbus_subchannel_put(struct vmbus_channel **, int);
|
||||
void vmbus_subchannel_rel(struct vmbus_channel **, int);
|
||||
void vmbus_subchannel_drain(struct vmbus_channel *);
|
||||
|
||||
#endif /* _VMBUSVAR_H_ */
|
||||
|
|
Loading…
Reference in New Issue