diff options
Diffstat (limited to 'sys/dev/hyperv')
-rw-r--r-- | sys/dev/hyperv/hvsock/hv_sock.c | 2 | ||||
-rw-r--r-- | sys/dev/hyperv/input/hv_hid.c | 8 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/if_hn.c | 39 | ||||
-rw-r--r-- | sys/dev/hyperv/pcib/vmbus_pcib.c | 7 | ||||
-rw-r--r-- | sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c | 9 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/aarch64/hyperv_machdep.c | 7 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hyperv.c | 63 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hyperv_mmu.c | 308 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hyperv_mmu.h | 57 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hyperv_var.h | 11 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus.c | 136 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_chan.c | 18 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_chanvar.h | 1 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_et.c | 4 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_reg.h | 10 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_var.h | 57 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_xact.c | 2 |
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); |