aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/hyperv
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hyperv')
-rw-r--r--sys/dev/hyperv/hvsock/hv_sock.c2
-rw-r--r--sys/dev/hyperv/input/hv_hid.c8
-rw-r--r--sys/dev/hyperv/netvsc/if_hn.c39
-rw-r--r--sys/dev/hyperv/pcib/vmbus_pcib.c7
-rw-r--r--sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c9
-rw-r--r--sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c7
-rw-r--r--sys/dev/hyperv/vmbus/hyperv.c63
-rw-r--r--sys/dev/hyperv/vmbus/hyperv_mmu.c308
-rw-r--r--sys/dev/hyperv/vmbus/hyperv_mmu.h57
-rw-r--r--sys/dev/hyperv/vmbus/hyperv_var.h11
-rw-r--r--sys/dev/hyperv/vmbus/vmbus.c136
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_chan.c18
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_chanvar.h1
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_et.c4
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_reg.h10
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_var.h57
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_xact.c2
17 files changed, 649 insertions, 90 deletions
diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c
index 8072765f2d5b..5a69eaa2b47b 100644
--- a/sys/dev/hyperv/hvsock/hv_sock.c
+++ b/sys/dev/hyperv/hvsock/hv_sock.c
@@ -1461,7 +1461,7 @@ hvsock_open_conn_passive(struct vmbus_channel *chan, struct socket *so,
}
/*
- * Create a new socket. This will call pru_attach to complete
+ * Create a new socket. This will call pr_attach() to complete
* the socket initialization and put the new socket onto
* listening socket's sol_incomp list, waiting to be promoted
* to sol_comp list.
diff --git a/sys/dev/hyperv/input/hv_hid.c b/sys/dev/hyperv/input/hv_hid.c
index b8fc9605bf67..ec68581d63a8 100644
--- a/sys/dev/hyperv/input/hv_hid.c
+++ b/sys/dev/hyperv/input/hv_hid.c
@@ -436,16 +436,14 @@ hv_hid_attach(device_t dev)
ret = ENODEV;
goto out;
}
- child = device_add_child(sc->dev, "hidbus", -1);
+ child = device_add_child(sc->dev, "hidbus", DEVICE_UNIT_ANY);
if (child == NULL) {
device_printf(sc->dev, "failed to add hidbus\n");
ret = ENOMEM;
goto out;
}
device_set_ivars(child, &sc->hdi);
- ret = bus_generic_attach(dev);
- if (ret != 0)
- device_printf(sc->dev, "failed to attach hidbus\n");
+ bus_attach_children(dev);
out:
if (ret != 0)
hv_hid_detach(dev);
@@ -459,7 +457,7 @@ hv_hid_detach(device_t dev)
int ret;
sc = device_get_softc(dev);
- ret = device_delete_children(dev);
+ ret = bus_generic_detach(dev);
if (ret != 0)
return (ret);
if (sc->hs_xact_ctx != NULL)
diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c
index 9f51f5b32199..ab7671025107 100644
--- a/sys/dev/hyperv/netvsc/if_hn.c
+++ b/sys/dev/hyperv/netvsc/if_hn.c
@@ -898,7 +898,7 @@ hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
th = mtodo(m_head, ehlen + iphlen);
- if (th->th_flags & TH_SYN)
+ if (tcp_get_flags(th) & TH_SYN)
*tcpsyn = 1;
return (m_head);
}
@@ -2355,7 +2355,7 @@ hn_attach(device_t dev)
}
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rsc_switch",
- CTLTYPE_UINT | CTLFLAG_RW, sc, 0, hn_rsc_sysctl, "A",
+ CTLTYPE_UINT | CTLFLAG_RW, sc, 0, hn_rsc_sysctl, "I",
"switch to rsc");
/*
@@ -4523,24 +4523,22 @@ static int
hn_rsc_sysctl(SYSCTL_HANDLER_ARGS)
{
struct hn_softc *sc = arg1;
- uint32_t mtu;
+ int rsc_ctrl, mtu;
int error;
- HN_LOCK(sc);
- error = hn_rndis_get_mtu(sc, &mtu);
- if (error) {
- if_printf(sc->hn_ifp, "failed to get mtu\n");
- goto back;
- }
- error = SYSCTL_OUT(req, &(sc->hn_rsc_ctrl), sizeof(sc->hn_rsc_ctrl));
+
+ rsc_ctrl = sc->hn_rsc_ctrl;
+ error = sysctl_handle_int(oidp, &rsc_ctrl, 0, req);
if (error || req->newptr == NULL)
- goto back;
+ return (error);
+
+ if (sc->hn_rsc_ctrl != rsc_ctrl) {
+ HN_LOCK(sc);
+ sc->hn_rsc_ctrl = rsc_ctrl;
+ mtu = if_getmtu(sc->hn_ifp);
+ error = hn_rndis_reconf_offload(sc, mtu);
+ HN_UNLOCK(sc);
+ }
- error = SYSCTL_IN(req, &(sc->hn_rsc_ctrl), sizeof(sc->hn_rsc_ctrl));
- if (error)
- goto back;
- error = hn_rndis_reconf_offload(sc, mtu);
-back:
- HN_UNLOCK(sc);
return (error);
}
#ifndef RSS
@@ -5131,7 +5129,7 @@ hn_destroy_rx_data(struct hn_softc *sc)
if (sc->hn_rxbuf != NULL) {
if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
- contigfree(sc->hn_rxbuf, HN_RXBUF_SIZE, M_DEVBUF);
+ free(sc->hn_rxbuf, M_DEVBUF);
else
device_printf(sc->hn_dev, "RXBUF is referenced\n");
sc->hn_rxbuf = NULL;
@@ -5146,8 +5144,7 @@ hn_destroy_rx_data(struct hn_softc *sc)
if (rxr->hn_br == NULL)
continue;
if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
- contigfree(rxr->hn_br, HN_TXBR_SIZE + HN_RXBR_SIZE,
- M_DEVBUF);
+ free(rxr->hn_br, M_DEVBUF);
} else {
device_printf(sc->hn_dev,
"%dth channel bufring is referenced", i);
@@ -5649,7 +5646,7 @@ hn_destroy_tx_data(struct hn_softc *sc)
if (sc->hn_chim != NULL) {
if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
- contigfree(sc->hn_chim, HN_CHIM_SIZE, M_DEVBUF);
+ free(sc->hn_chim, M_DEVBUF);
} else {
device_printf(sc->hn_dev,
"chimney sending buffer is referenced");
diff --git a/sys/dev/hyperv/pcib/vmbus_pcib.c b/sys/dev/hyperv/pcib/vmbus_pcib.c
index f6237535cce3..7b755e5f9c63 100644
--- a/sys/dev/hyperv/pcib/vmbus_pcib.c
+++ b/sys/dev/hyperv/pcib/vmbus_pcib.c
@@ -25,7 +25,6 @@
*/
#include <sys/cdefs.h>
-#ifdef NEW_PCIB
#include "opt_acpi.h"
#include <sys/param.h>
@@ -1565,14 +1564,14 @@ vmbus_pcib_attach(device_t dev)
vmbus_pcib_prepopulate_bars(hbus);
- hbus->pci_bus = device_add_child(dev, "pci", -1);
+ hbus->pci_bus = device_add_child(dev, "pci", DEVICE_UNIT_ANY);
if (!hbus->pci_bus) {
device_printf(dev, "failed to create pci bus\n");
ret = ENXIO;
goto vmbus_close;
}
- bus_generic_attach(dev);
+ bus_attach_children(dev);
hbus->state = hv_pcibus_installed;
@@ -2042,5 +2041,3 @@ DEFINE_CLASS_0(pcib, vmbus_pcib_driver, vmbus_pcib_methods,
DRIVER_MODULE(vmbus_pcib, vmbus, vmbus_pcib_driver, 0, 0);
MODULE_DEPEND(vmbus_pcib, vmbus, 1, 1, 1);
MODULE_DEPEND(vmbus_pcib, pci, 1, 1, 1);
-
-#endif /* NEW_PCIB */
diff --git a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
index eeec169baac5..29a88e76a579 100644
--- a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
+++ b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
@@ -954,13 +954,18 @@ storvsc_init_requests(device_t dev)
bus_get_dma_tag(dev), /* parent */
1, /* alignment */
PAGE_SIZE, /* boundary */
+#if defined(__i386__) && defined(PAE)
+ BUS_SPACE_MAXADDR_48BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR_48BIT, /* highaddr */
+#else
BUS_SPACE_MAXADDR, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
+#endif
NULL, NULL, /* filter, filterarg */
STORVSC_DATA_SIZE_MAX, /* maxsize */
STORVSC_DATA_SEGCNT_MAX, /* nsegments */
STORVSC_DATA_SEGSZ_MAX, /* maxsegsize */
- 0, /* flags */
+ BUS_DMA_KEEP_PG_OFFSET, /* flags */
NULL, /* lockfunc */
NULL, /* lockfuncarg */
&sc->storvsc_req_dtag);
@@ -1828,7 +1833,6 @@ storvsc_xferbuf_prepare(void *arg, bus_dma_segment_t *segs, int nsegs, int error
for (i = 0; i < nsegs; i++) {
#ifdef INVARIANTS
-#if !defined(__aarch64__)
if (nsegs > 1) {
if (i == 0) {
KASSERT((segs[i].ds_addr & PAGE_MASK) +
@@ -1849,7 +1853,6 @@ storvsc_xferbuf_prepare(void *arg, bus_dma_segment_t *segs, int nsegs, int error
}
}
#endif
-#endif
prplist->gpa_page[i] = atop(segs[i].ds_addr);
}
reqp->prp_cnt = nsegs;
diff --git a/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c b/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c
index dbb6aac2de31..e808cc081535 100644
--- a/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c
+++ b/sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c
@@ -50,10 +50,10 @@
void
arm_hv_set_vreg(u32 msr, u64 value)
{
- arm_smccc_hvc(HV_FUNC_ID,
+ arm_smccc_invoke_hvc(HV_FUNC_ID,
HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
HV_HYPERCALL_REP_COMP_1,
- HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr, 0, value, 0, NULL);
+ HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr, 0, value, NULL);
}
void
@@ -95,8 +95,7 @@ hypercall_md(volatile void *hc_addr, uint64_t in_val, uint64_t in_paddr,
{
struct arm_smccc_res res;
- arm_smccc_hvc(HV_FUNC_ID, in_val, in_paddr, out_paddr, 0, 0, 0, 0,
- &res);
+ arm_smccc_invoke_hvc(HV_FUNC_ID, in_val, in_paddr, out_paddr, &res);
return (res.a0);
}
diff --git a/sys/dev/hyperv/vmbus/hyperv.c b/sys/dev/hyperv/vmbus/hyperv.c
index e0e85a022090..1f85203146d0 100644
--- a/sys/dev/hyperv/vmbus/hyperv.c
+++ b/sys/dev/hyperv/vmbus/hyperv.c
@@ -35,6 +35,7 @@
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/timetc.h>
+#include <sys/cpuset.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -50,6 +51,7 @@
#include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
#include <dev/hyperv/vmbus/x86/hyperv_reg.h>
#endif
+#include <dev/hyperv/vmbus/vmbus_var.h>
#include <dev/hyperv/vmbus/hyperv_common_reg.h>
#include <dev/hyperv/vmbus/hyperv_var.h>
@@ -72,10 +74,12 @@
MSR_HV_GUESTID_OSID_FREEBSD | \
MSR_HV_GUESTID_OSTYPE_FREEBSD)
+
static bool hyperv_identify(void);
static void hypercall_memfree(void);
static struct hypercall_ctx hypercall_context;
+
uint64_t
hypercall_post_message(bus_addr_t msg_paddr)
{
@@ -90,6 +94,65 @@ hypercall_signal_event(bus_addr_t monprm_paddr)
HYPERCALL_SIGNAL_EVENT, monprm_paddr, 0);
}
+static inline int hv_result(uint64_t status)
+{
+ return status & HV_HYPERCALL_RESULT_MASK;
+}
+
+static inline bool hv_result_success(uint64_t status)
+{
+ return hv_result(status) == HV_STATUS_SUCCESS;
+}
+
+static inline unsigned int hv_repcomp(uint64_t status)
+{
+ /* Bits [43:32] of status have 'Reps completed' data. */
+ return ((status & HV_HYPERCALL_REP_COMP_MASK) >>
+ HV_HYPERCALL_REP_COMP_OFFSET);
+}
+
+/*
+ * Rep hypercalls. Callers of this functions are supposed to ensure that
+ * rep_count and varhead_size comply with Hyper-V hypercall definition.
+ */
+uint64_t
+hv_do_rep_hypercall(uint16_t code, uint16_t rep_count, uint16_t varhead_size,
+ uint64_t input, uint64_t output)
+{
+ uint64_t control = code;
+ uint64_t status;
+ uint16_t rep_comp;
+
+ control |= (uint64_t)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
+ control |= (uint64_t)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
+
+ do {
+ status = hypercall_do_md(control, input, output);
+ if (!hv_result_success(status))
+ return status;
+
+ rep_comp = hv_repcomp(status);
+
+ control &= ~HV_HYPERCALL_REP_START_MASK;
+ control |= (uint64_t)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
+
+ } while (rep_comp < rep_count);
+ if (hv_result_success(status))
+ return HV_STATUS_SUCCESS;
+
+ return status;
+}
+
+uint64_t
+hypercall_do_md(uint64_t input_val, uint64_t input_addr, uint64_t out_addr)
+{
+ uint64_t phys_inaddr, phys_outaddr;
+ phys_inaddr = input_addr ? vtophys(input_addr) : 0;
+ phys_outaddr = out_addr ? vtophys(out_addr) : 0;
+ return hypercall_md(hypercall_context.hc_addr,
+ input_val, phys_inaddr, phys_outaddr);
+}
+
int
hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz)
{
diff --git a/sys/dev/hyperv/vmbus/hyperv_mmu.c b/sys/dev/hyperv/vmbus/hyperv_mmu.c
new file mode 100644
index 000000000000..8e982974161c
--- /dev/null
+++ b/sys/dev/hyperv/vmbus/hyperv_mmu.c
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 2009-2012,2016-2024 Microsoft Corp.
+ * Copyright (c) 2012 NetApp Inc.
+ * Copyright (c) 2012 Citrix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/kdb.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/x86/hyperv_reg.h>
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/vmbus/hyperv_var.h>
+#include <dev/hyperv/vmbus/vmbus_reg.h>
+#include <dev/hyperv/vmbus/vmbus_var.h>
+#include <dev/hyperv/vmbus/hyperv_common_reg.h>
+#include "hyperv_mmu.h"
+
+static inline int fill_gva_list(uint64_t gva_list[],
+ unsigned long start, unsigned long end)
+{
+ int gva_n = 0;
+ unsigned long cur = start, diff;
+
+ do {
+ diff = end > cur ? end - cur : 0;
+
+ gva_list[gva_n] = cur;
+ /*
+ * Lower 12 bits encode the number of additional
+ * pages to flush (in addition to the 'cur' page).
+ */
+ if (diff >= HV_TLB_FLUSH_UNIT) {
+ gva_list[gva_n] |= PAGE_MASK;
+ cur += HV_TLB_FLUSH_UNIT;
+ } else if (diff) {
+ gva_list[gva_n] |= (diff - 1) >> PAGE_SHIFT;
+ cur = end;
+ }
+
+ gva_n++;
+
+ } while (cur < end);
+
+ return gva_n;
+}
+
+
+inline int hv_cpumask_to_vpset(struct hv_vpset *vpset,
+ const cpuset_t *cpus, struct vmbus_softc * sc)
+{
+ int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
+ int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK;
+
+ /*
+ * vpset.valid_bank_mask can represent up to
+ * HV_MAX_SPARSE_VCPU_BANKS banks
+ */
+ if (max_vcpu_bank >= HV_MAX_SPARSE_VCPU_BANKS)
+ return 0;
+
+ /*
+ * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex
+ * structs are not cleared between calls, we risk flushing unneeded
+ * vCPUs otherwise.
+ */
+ for (vcpu_bank = 0; vcpu_bank <= max_vcpu_bank; vcpu_bank++)
+ vpset->bank_contents[vcpu_bank] = 0;
+
+ /*
+ * Some banks may end up being empty but this is acceptable.
+ */
+ CPU_FOREACH_ISSET(cpu, cpus) {
+ vcpu = VMBUS_PCPU_GET(sc, vcpuid, cpu);
+ if (vcpu == -1)
+ return -1;
+ vcpu_bank = vcpu / HV_VCPUS_PER_SPARSE_BANK;
+ vcpu_offset = vcpu % HV_VCPUS_PER_SPARSE_BANK;
+ set_bit(vcpu_offset, (unsigned long *)
+ &vpset->bank_contents[vcpu_bank]);
+ if (vcpu_bank >= nr_bank)
+ nr_bank = vcpu_bank + 1;
+ }
+ vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
+ return nr_bank;
+}
+
+
+
+
+void
+hv_vm_tlb_flush(pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2,
+ enum invl_op_codes op, struct vmbus_softc *sc, smp_invl_local_cb_t curcpu_cb)
+{
+ cpuset_t tmp_mask, mask;
+ struct hyperv_tlb_flush *flush;
+ int cpu, vcpu;
+ int max_gvas, gva_n;
+ uint64_t status = 0;
+ uint64_t cr3;
+
+ /*
+ * Hyper-V doesn't handle the invalidating cache. Let system handle it.
+ */
+ if (op == INVL_OP_CACHE)
+ return smp_targeted_tlb_shootdown_native(pmap, addr1, addr2,
+ curcpu_cb, op);
+
+ flush = *VMBUS_PCPU_PTR(sc, cpu_mem, curcpu);
+ if (flush == NULL)
+ return smp_targeted_tlb_shootdown_native(pmap, addr1, addr2,
+ curcpu_cb, op);
+ /*
+ * It is not necessary to signal other CPUs while booting or
+ * when in the debugger.
+ */
+ if (__predict_false(kdb_active || KERNEL_PANICKED() || !smp_started))
+ goto local_cb;
+
+ KASSERT(curthread->td_pinned > 0, ("curthread not pinned"));
+
+ /*
+ * Make a stable copy of the set of CPUs on which the pmap is active.
+ * See if we have to interrupt other CPUs.
+ */
+ CPU_COPY(pmap_invalidate_cpu_mask(pmap), &tmp_mask);
+ CPU_COPY(pmap_invalidate_cpu_mask(pmap), &mask);
+ CPU_CLR(curcpu, &tmp_mask);
+ if (CPU_EMPTY(&tmp_mask))
+ goto local_cb;
+
+ /*
+ * Initiator must have interrupts enabled, which prevents
+ * non-invalidation IPIs that take smp_ipi_mtx spinlock,
+ * from deadlocking with us. On the other hand, preemption
+ * must be disabled to pin initiator to the instance of the
+ * pcpu pc_smp_tlb data and scoreboard line.
+ */
+ KASSERT((read_rflags() & PSL_I) != 0,
+ ("hv_tlb_flush: interrupts disabled"));
+ critical_enter();
+ flush->processor_mask = 0;
+ cr3 = pmap->pm_cr3;
+
+ if (op == INVL_OP_TLB || op == INVL_OP_TLB_INVPCID ||
+ op == INVL_OP_TLB_INVPCID_PTI || op == INVL_OP_TLB_PCID) {
+ flush->address_space = 0;
+ flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
+ } else {
+
+ flush->address_space = cr3;
+ flush->address_space &= ~CR3_PCID_MASK;
+ flush->flags = 0;
+ }
+ if(CPU_CMP(&mask, &all_cpus) == 0) {
+ flush->flags |= HV_FLUSH_ALL_PROCESSORS;
+ } else {
+ if (CPU_FLS(&mask) < mp_ncpus && CPU_FLS(&mask) >= 64)
+ goto do_ex_hypercall;
+
+ CPU_FOREACH_ISSET(cpu, &mask) {
+ vcpu = VMBUS_PCPU_GET(sc, vcpuid, cpu);
+ if (vcpu >= 64)
+ goto do_ex_hypercall;
+
+ set_bit(vcpu, &flush->processor_mask);
+ }
+ if (!flush->processor_mask )
+ goto native;
+ }
+ max_gvas = (PAGE_SIZE - sizeof(*flush)) / sizeof(flush->gva_list[0]);
+ if (addr2 == 0) {
+ flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
+ status = hypercall_do_md(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
+ (uint64_t)flush, (uint64_t)NULL);
+ } else if ((addr2 && (addr2 -addr1)/HV_TLB_FLUSH_UNIT) > max_gvas) {
+ status = hypercall_do_md(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
+ (uint64_t)flush, (uint64_t)NULL);
+ } else {
+ gva_n = fill_gva_list(flush->gva_list, addr1, addr2);
+
+ status = hv_do_rep_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST,
+ gva_n, 0, (uint64_t)flush, (uint64_t)NULL);
+
+ }
+ if(status)
+ goto native;
+ sched_unpin();
+ critical_exit();
+ return;
+
+local_cb:
+ critical_enter();
+ curcpu_cb(pmap, addr1, addr2);
+ sched_unpin();
+ critical_exit();
+ return;
+do_ex_hypercall:
+ status = hv_flush_tlb_others_ex(pmap, addr1, addr2, mask, op, sc);
+ if (status)
+ goto native;
+ sched_unpin();
+ critical_exit();
+ return;
+native:
+ critical_exit();
+ return smp_targeted_tlb_shootdown_native(pmap, addr1,
+ addr2, curcpu_cb, op);
+}
+
+uint64_t
+hv_flush_tlb_others_ex(pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2,
+ const cpuset_t mask, enum invl_op_codes op, struct vmbus_softc *sc)
+{
+ int nr_bank = 0, max_gvas, gva_n;
+ struct hv_tlb_flush_ex *flush;
+ if(*VMBUS_PCPU_PTR(sc, cpu_mem, curcpu) == NULL)
+ return EINVAL;
+ flush = *VMBUS_PCPU_PTR(sc, cpu_mem, curcpu);
+ uint64_t status = 0;
+ uint64_t cr3;
+
+ if (!(hyperv_recommends & HYPERV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
+ return EINVAL;
+
+ cr3 = pmap->pm_cr3;
+ if (op == INVL_OP_TLB) {
+ flush->address_space = 0;
+ flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
+ } else {
+
+ flush->address_space = cr3;
+ flush->address_space &= ~CR3_PCID_MASK;
+ flush->flags = 0;
+ }
+
+ flush->hv_vp_set.valid_bank_mask = 0;
+
+ flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
+ nr_bank = hv_cpumask_to_vpset(&flush->hv_vp_set, &mask, sc);
+ if (nr_bank < 0)
+ return EINVAL;
+
+ /*
+ * We can flush not more than max_gvas with one hypercall. Flush the
+ * whole address space if we were asked to do more.
+ */
+ max_gvas = (PAGE_SIZE - sizeof(*flush) - nr_bank *
+ sizeof(flush->hv_vp_set.bank_contents[0])) /
+ sizeof(flush->hv_vp_set.bank_contents[0]);
+
+ if (addr2 == 0) {
+ flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+ 0, nr_bank, (uint64_t)flush, (uint64_t)NULL);
+ } else if (addr2 &&
+ ((addr2 - addr1)/HV_TLB_FLUSH_UNIT) > max_gvas) {
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+ 0, nr_bank, (uint64_t)flush, (uint64_t)NULL);
+ } else {
+ gva_n = fill_gva_list(&flush->hv_vp_set.bank_contents[nr_bank],
+ addr1, addr2);
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
+ gva_n, nr_bank, (uint64_t)flush, (uint64_t)NULL);
+ }
+ return status;
+}
diff --git a/sys/dev/hyperv/vmbus/hyperv_mmu.h b/sys/dev/hyperv/vmbus/hyperv_mmu.h
new file mode 100644
index 000000000000..e62948d74181
--- /dev/null
+++ b/sys/dev/hyperv/vmbus/hyperv_mmu.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2009-2012,2016-2024 Microsoft Corp.
+ * Copyright (c) 2012 NetApp Inc.
+ * Copyright (c) 2012 Citrix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _HYPERV_MMU_H_
+#define _HYPERV_MMU_H_
+
+#include "vmbus_var.h"
+
+#define HV_VCPUS_PER_SPARSE_BANK (64)
+#define HV_MAX_SPARSE_VCPU_BANKS (64)
+
+
+struct hyperv_tlb_flush {
+ uint64_t address_space;
+ uint64_t flags;
+ uint64_t processor_mask;
+ uint64_t gva_list[];
+}__packed;
+
+struct hv_vpset {
+ uint64_t format;
+ uint64_t valid_bank_mask;
+ uint64_t bank_contents[];
+} __packed;
+
+struct hv_tlb_flush_ex {
+ uint64_t address_space;
+ uint64_t flags;
+ struct hv_vpset hv_vp_set;
+} __packed;
+
+#endif
diff --git a/sys/dev/hyperv/vmbus/hyperv_var.h b/sys/dev/hyperv/vmbus/hyperv_var.h
index 67f6cc4ef706..62cce9026ab0 100644
--- a/sys/dev/hyperv/vmbus/hyperv_var.h
+++ b/sys/dev/hyperv/vmbus/hyperv_var.h
@@ -33,7 +33,18 @@ struct hypercall_ctx {
void *hc_addr;
vm_paddr_t hc_paddr;
};
+
uint64_t hypercall_post_message(bus_addr_t msg_paddr);
uint64_t hypercall_signal_event(bus_addr_t monprm_paddr);
+uint64_t hypercall_do_md(uint64_t input, uint64_t in_addr,
+ uint64_t out_addr);
+struct hv_vpset;
+struct vmbus_softc;
+uint64_t
+hv_do_rep_hypercall(uint16_t code, uint16_t rep_count, uint16_t varhead_size,
+ uint64_t input, uint64_t output);
+int
+hv_cpumask_to_vpset(struct hv_vpset *vpset, const cpuset_t *cpus,
+ struct vmbus_softc *sc);
#endif /* !_HYPERV_VAR_H_ */
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index 3cc210a5003c..115d4af599ee 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -139,6 +139,10 @@ static void vmbus_event_proc_dummy(struct vmbus_softc *,
int);
static bus_dma_tag_t vmbus_get_dma_tag(device_t parent, device_t child);
static struct vmbus_softc *vmbus_sc;
+#if defined(__x86_64__)
+static int vmbus_alloc_cpu_mem(struct vmbus_softc *sc);
+static void vmbus_free_cpu_mem(struct vmbus_softc *sc);
+#endif
SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
"Hyper-V vmbus");
@@ -146,6 +150,13 @@ SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
static int vmbus_pin_evttask = 1;
SYSCTL_INT(_hw_vmbus, OID_AUTO, pin_evttask, CTLFLAG_RDTUN,
&vmbus_pin_evttask, 0, "Pin event tasks to their respective CPU");
+
+#if defined(__x86_64__)
+static int hv_tlb_hcall = 1;
+SYSCTL_INT(_hw_vmbus, OID_AUTO, tlb_hcall , CTLFLAG_RDTUN,
+ &hv_tlb_hcall, 0, "Use Hyper_V hyercall for tlb flush");
+#endif
+
uint32_t vmbus_current_version;
static const uint32_t vmbus_version[] = {
@@ -208,6 +219,8 @@ static driver_t vmbus_driver = {
sizeof(struct vmbus_softc)
};
+uint32_t hv_max_vp_index;
+
DRIVER_MODULE(vmbus, pcib, vmbus_driver, NULL, NULL);
DRIVER_MODULE(vmbus, acpi_syscontainer, vmbus_driver, NULL, NULL);
@@ -546,8 +559,8 @@ vmbus_scan(struct vmbus_softc *sc)
/*
* Identify, probe and attach for non-channel devices.
*/
- bus_generic_probe(sc->vmbus_dev);
- bus_generic_attach(sc->vmbus_dev);
+ bus_identify_children(sc->vmbus_dev);
+ bus_attach_children(sc->vmbus_dev);
/*
* This taskqueue serializes vmbus devices' attach and detach
@@ -748,6 +761,9 @@ vmbus_synic_setup(void *xsc)
VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0;
}
+ if (VMBUS_PCPU_GET(sc, vcpuid, cpu) > hv_max_vp_index)
+ hv_max_vp_index = VMBUS_PCPU_GET(sc, vcpuid, cpu);
+
/*
* Setup the SynIC message.
*/
@@ -786,6 +802,16 @@ vmbus_synic_setup(void *xsc)
WRMSR(MSR_HV_SCONTROL, val);
}
+#if defined(__x86_64__)
+void
+hyperv_vm_tlb_flush(pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2,
+ smp_invl_local_cb_t curcpu_cb, enum invl_op_codes op)
+{
+ struct vmbus_softc *sc = vmbus_get_softc();
+ return hv_vm_tlb_flush(pmap, addr1, addr2, op, sc, curcpu_cb);
+}
+#endif /*__x86_64__*/
+
static void
vmbus_synic_teardown(void *arg)
{
@@ -874,29 +900,27 @@ vmbus_dma_free(struct vmbus_softc *sc)
int cpu;
if (sc->vmbus_evtflags != NULL) {
- contigfree(sc->vmbus_evtflags, PAGE_SIZE, M_DEVBUF);
+ free(sc->vmbus_evtflags, M_DEVBUF);
sc->vmbus_evtflags = NULL;
sc->vmbus_rx_evtflags = NULL;
sc->vmbus_tx_evtflags = NULL;
}
if (sc->vmbus_mnf1 != NULL) {
- contigfree(sc->vmbus_mnf1, PAGE_SIZE, M_DEVBUF);
+ free(sc->vmbus_mnf1, M_DEVBUF);
sc->vmbus_mnf1 = NULL;
}
if (sc->vmbus_mnf2 != NULL) {
- contigfree(sc->vmbus_mnf2, sizeof(struct vmbus_mnf), M_DEVBUF);
+ free(sc->vmbus_mnf2, M_DEVBUF);
sc->vmbus_mnf2 = NULL;
}
CPU_FOREACH(cpu) {
if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
- contigfree(VMBUS_PCPU_GET(sc, message, cpu), PAGE_SIZE,
- M_DEVBUF);
+ free(VMBUS_PCPU_GET(sc, message, cpu), M_DEVBUF);
VMBUS_PCPU_GET(sc, message, cpu) = NULL;
}
if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) {
- contigfree(VMBUS_PCPU_GET(sc, event_flags, cpu),
- PAGE_SIZE, M_DEVBUF);
+ free(VMBUS_PCPU_GET(sc, event_flags, cpu), M_DEVBUF);
VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL;
}
}
@@ -989,7 +1013,8 @@ vmbus_add_child(struct vmbus_channel *chan)
device_t parent = sc->vmbus_dev;
bus_topo_lock();
- chan->ch_dev = device_add_child(parent, NULL, -1);
+
+ chan->ch_dev = device_add_child(parent, NULL, DEVICE_UNIT_ANY);
if (chan->ch_dev == NULL) {
bus_topo_unlock();
device_printf(parent, "device_add_child for chan%u failed\n",
@@ -1043,15 +1068,12 @@ vmbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
device_t parent = device_get_parent(dev);
struct resource *res;
-#ifdef NEW_PCIB
if (type == SYS_RES_MEMORY) {
struct vmbus_softc *sc = device_get_softc(dev);
res = pcib_host_res_alloc(&sc->vmbus_mmio_res, child, type,
rid, start, end, count, flags);
- } else
-#endif
- {
+ } else {
res = BUS_ALLOC_RESOURCE(parent, child, type, rid, start,
end, count, flags);
}
@@ -1132,7 +1154,6 @@ vmbus_get_eventtq_method(device_t bus, device_t dev __unused, int cpu)
return (VMBUS_PCPU_GET(sc, event_tq, cpu));
}
-#ifdef NEW_PCIB
#define VTPM_BASE_ADDR 0xfed40000
#define FOUR_GB (1ULL << 32)
@@ -1284,18 +1305,14 @@ vmbus_fb_mmio_res(device_t dev)
#endif /* aarch64 */
rman_res_t fb_start, fb_end, fb_count;
int fb_height, fb_width;
- caddr_t kmdp;
struct vmbus_softc *sc = device_get_softc(dev);
int rid = 0;
- kmdp = preload_search_by_type("elf kernel");
- if (kmdp == NULL)
- kmdp = preload_search_by_type("elf64 kernel");
- efifb = (struct efi_fb *)preload_search_info(kmdp,
+ efifb = (struct efi_fb *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_EFI_FB);
#if !defined(__aarch64__)
- vbefb = (struct vbe_fb *)preload_search_info(kmdp,
+ vbefb = (struct vbe_fb *)preload_search_info(preload_kmdp,
MODINFO_METADATA | MODINFOMD_VBE_FB);
#endif /* aarch64 */
if (efifb != NULL) {
@@ -1349,7 +1366,6 @@ vmbus_free_mmio_res(device_t dev)
if (hv_fb_res)
hv_fb_res = NULL;
}
-#endif /* NEW_PCIB */
static void
vmbus_identify(driver_t *driver, device_t parent)
@@ -1358,7 +1374,7 @@ vmbus_identify(driver_t *driver, device_t parent)
if (device_get_unit(parent) != 0 || vm_guest != VM_GUEST_HV ||
(hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
return;
- device_add_child(parent, "vmbus", -1);
+ device_add_child(parent, "vmbus", DEVICE_UNIT_ANY);
}
static int
@@ -1373,6 +1389,42 @@ vmbus_probe(device_t dev)
return (BUS_PROBE_DEFAULT);
}
+#if defined(__x86_64__)
+static int
+vmbus_alloc_cpu_mem(struct vmbus_softc *sc)
+{
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ void **hv_cpu_mem;
+
+ hv_cpu_mem = VMBUS_PCPU_PTR(sc, cpu_mem, cpu);
+ *hv_cpu_mem = contigmalloc(PAGE_SIZE, M_DEVBUF,
+ M_NOWAIT | M_ZERO, 0ul, ~0ul, PAGE_SIZE, 0);
+
+ if (*hv_cpu_mem == NULL)
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+vmbus_free_cpu_mem(struct vmbus_softc *sc)
+{
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ void **hv_cpu_mem;
+ hv_cpu_mem = VMBUS_PCPU_PTR(sc, cpu_mem, cpu);
+ if(*hv_cpu_mem != NULL) {
+ free(*hv_cpu_mem, M_DEVBUF);
+ *hv_cpu_mem = NULL;
+ }
+ }
+}
+#endif
+
/**
* @brief Main vmbus driver initialization routine.
*
@@ -1398,10 +1450,8 @@ vmbus_doattach(struct vmbus_softc *sc)
if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
return (0);
-#ifdef NEW_PCIB
vmbus_get_mmio_res(sc->vmbus_dev);
vmbus_fb_mmio_res(sc->vmbus_dev);
-#endif
sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
@@ -1462,6 +1512,25 @@ vmbus_doattach(struct vmbus_softc *sc)
if (ret != 0)
goto cleanup;
+#if defined(__x86_64__)
+ /*
+ * Alloc per cpu memory for tlb flush hypercall
+ */
+ if (hv_tlb_hcall) {
+ ret = vmbus_alloc_cpu_mem(sc);
+ if (ret != 0) {
+ hv_tlb_hcall = 0;
+ if (bootverbose)
+ device_printf(sc->vmbus_dev,
+ "cannot alloc contig memory for "
+ "cpu_mem, use system provided "
+ "tlb flush call.\n");
+
+ vmbus_free_cpu_mem(sc);
+ }
+ }
+#endif
+
/*
* Setup SynIC.
*/
@@ -1470,6 +1539,11 @@ vmbus_doattach(struct vmbus_softc *sc)
smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc);
sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
+#if defined(__x86_64__)
+ if (hv_tlb_hcall)
+ smp_targeted_tlb_shootdown = &hyperv_vm_tlb_flush;
+#endif
+
/*
* Initialize vmbus, e.g. connect to Hypervisor.
*/
@@ -1573,6 +1647,16 @@ vmbus_detach(device_t dev)
smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
}
+#if defined(__x86_64__)
+ /*
+ * Restore the tlb flush to native call
+ */
+ if (hv_tlb_hcall) {
+ smp_targeted_tlb_shootdown = &smp_targeted_tlb_shootdown_native;
+ vmbus_free_cpu_mem(sc);
+ }
+#endif
+
vmbus_intr_teardown(sc);
vmbus_dma_free(sc);
@@ -1585,9 +1669,7 @@ vmbus_detach(device_t dev)
mtx_destroy(&sc->vmbus_prichan_lock);
mtx_destroy(&sc->vmbus_chan_lock);
-#ifdef NEW_PCIB
vmbus_free_mmio_res(dev);
-#endif
#if defined(__aarch64__)
bus_release_resource(device_get_parent(dev), SYS_RES_IRQ, sc->vector,
diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c
index 0922470d4672..7ea60a499c72 100644
--- a/sys/dev/hyperv/vmbus/vmbus_chan.c
+++ b/sys/dev/hyperv/vmbus/vmbus_chan.c
@@ -34,11 +34,11 @@
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <sys/stdarg.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <machine/atomic.h>
-#include <machine/stdarg.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@@ -341,8 +341,7 @@ vmbus_chan_open(struct vmbus_channel *chan, int txbr_size, int rxbr_size,
* Allocate the TX+RX bufrings.
*/
KASSERT(chan->ch_bufring == NULL, ("bufrings are allocated"));
- chan->ch_bufring_size = txbr_size + rxbr_size;
- chan->ch_bufring = contigmalloc(chan->ch_bufring_size, M_DEVBUF,
+ chan->ch_bufring = contigmalloc(txbr_size + rxbr_size, M_DEVBUF,
M_WAITOK | M_ZERO, 0ul, ~0ul, PAGE_SIZE, 0);
if (chan->ch_bufring == NULL) {
vmbus_chan_printf(chan, "bufring allocation failed\n");
@@ -368,8 +367,7 @@ vmbus_chan_open(struct vmbus_channel *chan, int txbr_size, int rxbr_size,
"leak %d bytes memory\n", chan->ch_id,
txbr_size + rxbr_size);
} else {
- contigfree(chan->ch_bufring, chan->ch_bufring_size,
- M_DEVBUF);
+ free(chan->ch_bufring, M_DEVBUF);
}
chan->ch_bufring = NULL;
}
@@ -939,7 +937,7 @@ disconnect:
* Destroy the TX+RX bufrings.
*/
if (chan->ch_bufring != NULL) {
- contigfree(chan->ch_bufring, chan->ch_bufring_size, M_DEVBUF);
+ free(chan->ch_bufring, M_DEVBUF);
chan->ch_bufring = NULL;
}
return (error);
@@ -1557,7 +1555,7 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags,
continue;
flags = atomic_swap_long(&event_flags[f], 0);
- chid_base = f << VMBUS_EVTFLAG_SHIFT;
+ chid_base = f * VMBUS_EVTFLAG_LEN;
while ((chid_ofs = ffsl(flags)) != 0) {
struct vmbus_channel *chan;
@@ -1601,7 +1599,7 @@ vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu)
eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) {
vmbus_event_flags_proc(sc, sc->vmbus_rx_evtflags,
- VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT);
+ VMBUS_CHAN_MAX_COMPAT / VMBUS_EVTFLAG_LEN);
}
}
@@ -1679,7 +1677,7 @@ vmbus_chan_free(struct vmbus_channel *chan)
KASSERT(chan->ch_poll_intvl == 0, ("chan%u: polling is activated",
chan->ch_id));
- contigfree(chan->ch_monprm, sizeof(struct hyperv_mon_param), M_DEVBUF);
+ free(chan->ch_monprm, M_DEVBUF);
mtx_destroy(&chan->ch_subchan_lock);
sx_destroy(&chan->ch_orphan_lock);
vmbus_rxbr_deinit(&chan->ch_rxbr);
@@ -1905,7 +1903,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
* Setup event flag.
*/
chan->ch_evtflag =
- &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT];
+ &sc->vmbus_tx_evtflags[chan->ch_id / VMBUS_EVTFLAG_LEN];
chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK);
/*
diff --git a/sys/dev/hyperv/vmbus/vmbus_chanvar.h b/sys/dev/hyperv/vmbus/vmbus_chanvar.h
index e88ada2dd274..c02ec24c70a1 100644
--- a/sys/dev/hyperv/vmbus/vmbus_chanvar.h
+++ b/sys/dev/hyperv/vmbus/vmbus_chanvar.h
@@ -123,7 +123,6 @@ struct vmbus_channel {
struct vmbus_channel *ch_prichan; /* owner primary chan */
void *ch_bufring; /* TX+RX bufrings */
- size_t ch_bufring_size;
uint32_t ch_bufring_gpadl;
struct task ch_attach_task; /* run in ch_mgmt_tq */
diff --git a/sys/dev/hyperv/vmbus/vmbus_et.c b/sys/dev/hyperv/vmbus/vmbus_et.c
index 4ff011cfd77e..33eb94daacd3 100644
--- a/sys/dev/hyperv/vmbus/vmbus_et.c
+++ b/sys/dev/hyperv/vmbus/vmbus_et.c
@@ -127,12 +127,12 @@ static void
vmbus_et_identify(driver_t *driver, device_t parent)
{
if (device_get_unit(parent) != 0 ||
- device_find_child(parent, VMBUS_ET_NAME, -1) != NULL ||
+ device_find_child(parent, VMBUS_ET_NAME, DEVICE_UNIT_ANY) != NULL ||
(hyperv_features & CPUID_HV_ET_MASK) != CPUID_HV_ET_MASK ||
hyperv_tc64 == NULL)
return;
- device_add_child(parent, VMBUS_ET_NAME, -1);
+ device_add_child(parent, VMBUS_ET_NAME, DEVICE_UNIT_ANY);
}
static int
diff --git a/sys/dev/hyperv/vmbus/vmbus_reg.h b/sys/dev/hyperv/vmbus/vmbus_reg.h
index 4aa729475b5d..76cdca0ebeb2 100644
--- a/sys/dev/hyperv/vmbus/vmbus_reg.h
+++ b/sys/dev/hyperv/vmbus/vmbus_reg.h
@@ -60,16 +60,10 @@ CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
* Hyper-V SynIC event flags
*/
-#ifdef __LP64__
-#define VMBUS_EVTFLAGS_MAX 32
-#define VMBUS_EVTFLAG_SHIFT 6
-#else
-#define VMBUS_EVTFLAGS_MAX 64
-#define VMBUS_EVTFLAG_SHIFT 5
-#endif
-#define VMBUS_EVTFLAG_LEN (1 << VMBUS_EVTFLAG_SHIFT)
+#define VMBUS_EVTFLAG_LEN (sizeof(u_long) * 8)
#define VMBUS_EVTFLAG_MASK (VMBUS_EVTFLAG_LEN - 1)
#define VMBUS_EVTFLAGS_SIZE 256
+#define VMBUS_EVTFLAGS_MAX (VMBUS_EVTFLAGS_SIZE / sizeof(u_long))
struct vmbus_evtflags {
u_long evt_flags[VMBUS_EVTFLAGS_MAX];
diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h
index 023d27c52cea..cadcaa45aae5 100644
--- a/sys/dev/hyperv/vmbus/vmbus_var.h
+++ b/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -32,6 +32,11 @@
#include <sys/taskqueue.h>
#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
#include <dev/pci/pcivar.h>
#include <dev/pci/pcib_private.h>
@@ -69,6 +74,9 @@ struct vmbus_pcpu_data {
uint32_t vcpuid; /* virtual cpuid */
int event_flags_cnt;/* # of event flags */
struct vmbus_evtflags *event_flags; /* event flags from host */
+#if defined(__x86_64__)
+ void *cpu_mem; /* For Hyper-V tlb hypercall */
+#endif
/* Rarely used fields */
struct taskqueue *event_tq; /* event taskq */
@@ -119,10 +127,8 @@ struct vmbus_softc {
struct intr_config_hook vmbus_intrhook;
-#ifdef NEW_PCIB
/* The list of usable MMIO ranges for PCIe pass-through */
struct pcib_host_resources vmbus_mmio_res;
-#endif
#if defined(__aarch64__)
struct resource *ires;
@@ -137,6 +143,40 @@ struct vmbus_softc {
#define VMBUS_PCPU_GET(sc, field, cpu) (sc)->vmbus_pcpu[(cpu)].field
#define VMBUS_PCPU_PTR(sc, field, cpu) &(sc)->vmbus_pcpu[(cpu)].field
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013
+#define HV_FLUSH_ALL_PROCESSORS BIT(0)
+#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
+#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2)
+#define HV_TLB_FLUSH_UNIT (4096 * PAGE_SIZE)
+
+
+#define BIT(n) (1ULL << (n))
+#define BITS_PER_LONG (sizeof(long) * NBBY)
+#define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define set_bit(i, a) \
+ atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define GENMASK_ULL(h, l) (((~0ULL) >> (64 - (h) - 1)) & ((~0ULL) << (l)))
+
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014
+#define HYPERV_X64_EX_PROCESSOR_MASKS_RECOMMENDED BIT(11)
+#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
+#define HV_STATUS_SUCCESS 0
+#define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32)
+#define HV_HYPERCALL_REP_COMP_OFFSET 32
+
+#define HV_HYPERCALL_VARHEAD_OFFSET 17
+
+#define HV_HYPERCALL_REP_START_MASK GENMASK_ULL(59, 48)
+#define HV_HYPERCALL_REP_START_OFFSET 48
+
+enum HV_GENERIC_SET_FORMAT {
+ HV_GENERIC_SET_SPARSE_4K,
+ HV_GENERIC_SET_ALL,
+};
struct vmbus_channel;
struct trapframe;
@@ -176,4 +216,17 @@ void vmbus_synic_setup1(void *xsc);
void vmbus_synic_teardown1(void);
int vmbus_setup_intr1(struct vmbus_softc *sc);
void vmbus_intr_teardown1(struct vmbus_softc *sc);
+
+extern uint32_t hv_max_vp_index;
+
+
+#if defined(__x86_64__)
+void hyperv_vm_tlb_flush(pmap_t, vm_offset_t,
+ vm_offset_t, smp_invl_local_cb_t, enum invl_op_codes);
+uint64_t hv_flush_tlb_others_ex(pmap_t, vm_offset_t, vm_offset_t,
+ cpuset_t, enum invl_op_codes, struct vmbus_softc *);
+void hv_vm_tlb_flush(pmap_t, vm_offset_t, vm_offset_t,
+ enum invl_op_codes, struct vmbus_softc *,
+ smp_invl_local_cb_t);
+#endif /* __x86_64__ */
#endif /* !_VMBUS_VAR_H_ */
diff --git a/sys/dev/hyperv/vmbus/vmbus_xact.c b/sys/dev/hyperv/vmbus/vmbus_xact.c
index f5f766f2c2fc..eb221ef92b2c 100644
--- a/sys/dev/hyperv/vmbus/vmbus_xact.c
+++ b/sys/dev/hyperv/vmbus/vmbus_xact.c
@@ -104,7 +104,7 @@ static void
vmbus_xact_free(struct vmbus_xact *xact)
{
- contigfree(xact->x_req, xact->x_ctx->xc_req_size, M_DEVBUF);
+ free(xact->x_req, M_DEVBUF);
free(xact->x_resp0, M_DEVBUF);
if (xact->x_priv != NULL)
free(xact->x_priv, M_DEVBUF);