MFC 301483,301484,301487,301488,301583,301588

301483
    hyperv: Move machine dependent bits into machine dependent files.

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6701

301484
    hyperv/vmbus: Define type for channel messages.

    And fix message processing; only channel messages are supported.

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6706

301487
    hyperv/vmbus: Factor out channel message processing

    This paves the way for further cleanup.

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6707

301488
    hyperv/vmbus: Constify channel message

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6708

301583
    hyperv/vmbus: Busdma-fy MNF and event flags.

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6744

301588
    hyperv/vmbus: Change tx_evtflags type to u_long to match vmbus_evtflags

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6745
This commit is contained in:
sephe 2016-06-24 02:30:14 +00:00
parent 33e55d7e3f
commit 4ea0d87306
14 changed files with 307 additions and 188 deletions

View File

@ -279,6 +279,7 @@ dev/hyperv/vmbus/hyperv.c optional hyperv
dev/hyperv/vmbus/hyperv_busdma.c optional hyperv
dev/hyperv/vmbus/vmbus.c optional hyperv
dev/hyperv/vmbus/vmbus_et.c optional hyperv
dev/hyperv/vmbus/amd64/hyperv_machdep.c optional hyperv
dev/hyperv/vmbus/amd64/vmbus_vector.S optional hyperv
dev/kbd/kbd.c optional atkbd | sc | ukbd | vt
dev/lindev/full.c optional lindev

View File

@ -255,6 +255,7 @@ dev/hyperv/vmbus/hyperv.c optional hyperv
dev/hyperv/vmbus/hyperv_busdma.c optional hyperv
dev/hyperv/vmbus/vmbus.c optional hyperv
dev/hyperv/vmbus/vmbus_et.c optional hyperv
dev/hyperv/vmbus/i386/hyperv_machdep.c optional hyperv
dev/hyperv/vmbus/i386/vmbus_vector.S optional hyperv
dev/ichwd/ichwd.c optional ichwd
dev/if_ndis/if_ndis.c optional ndis

View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2016 Microsoft Corp.
* 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/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <dev/hyperv/vmbus/hyperv_machdep.h>
uint64_t
hypercall_md(volatile void *hc_addr, uint64_t in_val,
uint64_t in_paddr, uint64_t out_paddr)
{
uint64_t status;
__asm__ __volatile__ ("mov %0, %%r8" : : "r" (out_paddr): "r8");
__asm__ __volatile__ ("call *%3" : "=a" (status) :
"c" (in_val), "d" (in_paddr), "m" (hc_addr));
return (status);
}

View File

@ -37,12 +37,16 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <machine/atomic.h>
#include <machine/bus.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
#include <dev/hyperv/vmbus/vmbus_reg.h>
#include <dev/hyperv/vmbus/vmbus_var.h>
static int vmbus_channel_create_gpadl_header(
@ -62,17 +66,16 @@ static void VmbusProcessChannelEvent(void* channel, int pending);
static void
vmbus_channel_set_event(hv_vmbus_channel *channel)
{
hv_vmbus_monitor_page *monitor_page;
if (channel->offer_msg.monitor_allocated) {
/* Each uint32_t represents 32 channels */
synch_set_bit((channel->offer_msg.child_rel_id & 31),
((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
+ ((channel->offer_msg.child_rel_id >> 5))));
struct vmbus_softc *sc = vmbus_get_softc();
hv_vmbus_monitor_page *monitor_page;
uint32_t chanid = channel->offer_msg.child_rel_id;
monitor_page = (hv_vmbus_monitor_page *)
hv_vmbus_g_connection.monitor_page_2;
atomic_set_long(
&sc->vmbus_tx_evtflags[chanid >> VMBUS_EVTFLAG_SHIFT],
1UL << (chanid & VMBUS_EVTFLAG_MASK));
monitor_page = sc->vmbus_mnf2;
synch_set_bit(channel->monitor_bit,
(uint32_t *)&monitor_page->
trigger_group[channel->monitor_group].u.pending);

View File

@ -43,20 +43,34 @@ __FBSDID("$FreeBSD$");
* Internal functions
*/
static void vmbus_channel_on_offer(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_offer_internal(void* context);
static void vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_offer_rescind(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_offer_rescind_internal(void* context);
static void vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr);
static void vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr);
typedef void (*vmbus_msg_handler)(const hv_vmbus_channel_msg_header *msg);
typedef struct hv_vmbus_channel_msg_table_entry {
hv_vmbus_channel_msg_type messageType;
vmbus_msg_handler messageHandler;
} hv_vmbus_channel_msg_table_entry;
static void vmbus_channel_on_offer_internal(void *context);
static void vmbus_channel_on_offer_rescind_internal(void *context);
static void vmbus_channel_on_offer(const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_open_result(
const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_offer_rescind(
const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_gpadl_created(
const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_gpadl_torndown(
const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_offers_delivered(
const hv_vmbus_channel_msg_header *hdr);
static void vmbus_channel_on_version_response(
const hv_vmbus_channel_msg_header *hdr);
/**
* Channel message dispatch table
*/
hv_vmbus_channel_msg_table_entry
static const hv_vmbus_channel_msg_table_entry
g_channel_message_table[HV_CHANNEL_MESSAGE_COUNT] = {
{ HV_CHANNEL_MESSAGE_INVALID,
NULL },
@ -387,12 +401,12 @@ vmbus_channel_select_defcpu(struct hv_vmbus_channel *channel)
* object to process the offer synchronously
*/
static void
vmbus_channel_on_offer(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_offer(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_offer_channel* offer;
hv_vmbus_channel_offer_channel* copied;
const hv_vmbus_channel_offer_channel *offer;
hv_vmbus_channel_offer_channel *copied;
offer = (hv_vmbus_channel_offer_channel*) hdr;
offer = (const hv_vmbus_channel_offer_channel *)hdr;
// copy offer data
copied = malloc(sizeof(*copied), M_DEVBUF, M_NOWAIT);
@ -465,12 +479,12 @@ vmbus_channel_on_offer_internal(void* context)
* synchronously
*/
static void
vmbus_channel_on_offer_rescind(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_offer_rescind(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_rescind_offer* rescind;
const hv_vmbus_channel_rescind_offer *rescind;
hv_vmbus_channel* channel;
rescind = (hv_vmbus_channel_rescind_offer*) hdr;
rescind = (const hv_vmbus_channel_rescind_offer *)hdr;
channel = hv_vmbus_g_connection.channels[rescind->child_rel_id];
if (channel == NULL)
@ -497,7 +511,8 @@ vmbus_channel_on_offer_rescind_internal(void *context)
* @brief Invoked when all offers have been delivered.
*/
static void
vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_offers_delivered(
const hv_vmbus_channel_msg_header *hdr __unused)
{
mtx_lock(&vmbus_chwait_lock);
@ -514,14 +529,14 @@ vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr)
* response and signal the requesting thread.
*/
static void
vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_open_result(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_open_result* result;
const hv_vmbus_channel_open_result *result;
hv_vmbus_channel_msg_info* msg_info;
hv_vmbus_channel_msg_header* requestHeader;
hv_vmbus_channel_open_channel* openMsg;
result = (hv_vmbus_channel_open_result*) hdr;
result = (const hv_vmbus_channel_open_result *)hdr;
/*
* Find the open msg, copy the result and signal/unblock the wait event
@ -556,14 +571,14 @@ vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr)
* response and signal the requesting thread.
*/
static void
vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_gpadl_created(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_gpadl_created* gpadl_created;
const hv_vmbus_channel_gpadl_created *gpadl_created;
hv_vmbus_channel_msg_info* msg_info;
hv_vmbus_channel_msg_header* request_header;
hv_vmbus_channel_gpadl_header* gpadl_header;
gpadl_created = (hv_vmbus_channel_gpadl_created*) hdr;
gpadl_created = (const hv_vmbus_channel_gpadl_created *)hdr;
/* Find the establish msg, copy the result and signal/unblock
* the wait event
@ -598,14 +613,14 @@ vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr)
* response and signal the requesting thread
*/
static void
vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_gpadl_torndown(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_gpadl_torndown* gpadl_torndown;
const hv_vmbus_channel_gpadl_torndown *gpadl_torndown;
hv_vmbus_channel_msg_info* msg_info;
hv_vmbus_channel_msg_header* requestHeader;
hv_vmbus_channel_gpadl_teardown* gpadlTeardown;
gpadl_torndown = (hv_vmbus_channel_gpadl_torndown*)hdr;
gpadl_torndown = (const hv_vmbus_channel_gpadl_torndown *)hdr;
/*
* Find the open msg, copy the result and signal/unblock the
@ -643,14 +658,14 @@ vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr)
* response and signal the requesting thread.
*/
static void
vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr)
vmbus_channel_on_version_response(const hv_vmbus_channel_msg_header *hdr)
{
hv_vmbus_channel_msg_info* msg_info;
hv_vmbus_channel_msg_header* requestHeader;
hv_vmbus_channel_initiate_contact* initiate;
hv_vmbus_channel_version_response* versionResponse;
const hv_vmbus_channel_version_response *versionResponse;
versionResponse = (hv_vmbus_channel_version_response*)hdr;
versionResponse = (const hv_vmbus_channel_version_response *)hdr;
mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
@ -834,3 +849,24 @@ vmbus_rel_subchan(struct hv_vmbus_channel **subchan, int subchan_cnt __unused)
free(subchan, M_TEMP);
}
void
vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
{
const hv_vmbus_channel_msg_table_entry *entry;
const hv_vmbus_channel_msg_header *hdr;
hv_vmbus_channel_msg_type msg_type;
hdr = (const hv_vmbus_channel_msg_header *)msg->msg_data;
msg_type = hdr->message_type;
if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
msg_type);
return;
}
entry = &g_channel_message_table[msg_type];
if (entry->messageHandler)
entry->messageHandler(hdr);
}

View File

@ -77,8 +77,8 @@ hv_vmbus_get_next_version(uint32_t current_ver)
* Negotiate the highest supported hypervisor version.
*/
static int
hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
uint32_t version)
hv_vmbus_negotiate_version(struct vmbus_softc *sc,
hv_vmbus_channel_msg_info *msg_info, uint32_t version)
{
int ret = 0;
hv_vmbus_channel_initiate_contact *msg;
@ -89,14 +89,9 @@ hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
msg->vmbus_version_requested = version;
msg->interrupt_page = hv_get_phys_addr(
hv_vmbus_g_connection.interrupt_page);
msg->monitor_page_1 = hv_get_phys_addr(
hv_vmbus_g_connection.monitor_page_1);
msg->monitor_page_2 = hv_get_phys_addr(
hv_vmbus_g_connection.monitor_page_2);
msg->interrupt_page = sc->vmbus_evtflags_dma.hv_paddr;
msg->monitor_page_1 = sc->vmbus_mnf1_dma.hv_paddr;
msg->monitor_page_2 = sc->vmbus_mnf2_dma.hv_paddr;
/**
* Add to list before we send the request since we may receive the
@ -153,7 +148,7 @@ hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
* Send a connect request on the partition service connection
*/
int
hv_vmbus_connect(void)
hv_vmbus_connect(struct vmbus_softc *sc)
{
int ret = 0;
uint32_t version;
@ -179,34 +174,6 @@ hv_vmbus_connect(void)
mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
NULL, MTX_DEF);
/**
* Setup the vmbus event connection for channel interrupt abstraction
* stuff
*/
hv_vmbus_g_connection.interrupt_page = malloc(
PAGE_SIZE, M_DEVBUF,
M_WAITOK | M_ZERO);
hv_vmbus_g_connection.recv_interrupt_page =
hv_vmbus_g_connection.interrupt_page;
hv_vmbus_g_connection.send_interrupt_page =
((uint8_t *) hv_vmbus_g_connection.interrupt_page +
(PAGE_SIZE >> 1));
/**
* Set up the monitor notification facility. The 1st page for
* parent->child and the 2nd page for child->parent
*/
hv_vmbus_g_connection.monitor_page_1 = malloc(
PAGE_SIZE,
M_DEVBUF,
M_WAITOK | M_ZERO);
hv_vmbus_g_connection.monitor_page_2 = malloc(
PAGE_SIZE,
M_DEVBUF,
M_WAITOK | M_ZERO);
msg_info = (hv_vmbus_channel_msg_info*)
malloc(sizeof(hv_vmbus_channel_msg_info) +
sizeof(hv_vmbus_channel_initiate_contact),
@ -220,7 +187,7 @@ hv_vmbus_connect(void)
version = HV_VMBUS_VERSION_CURRENT;
do {
ret = hv_vmbus_negotiate_version(msg_info, version);
ret = hv_vmbus_negotiate_version(sc, msg_info, version);
if (ret == EWOULDBLOCK) {
/*
* We timed out.
@ -254,14 +221,6 @@ hv_vmbus_connect(void)
mtx_destroy(&hv_vmbus_g_connection.channel_lock);
mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock);
if (hv_vmbus_g_connection.interrupt_page != NULL) {
free(hv_vmbus_g_connection.interrupt_page, M_DEVBUF);
hv_vmbus_g_connection.interrupt_page = NULL;
}
free(hv_vmbus_g_connection.monitor_page_1, M_DEVBUF);
free(hv_vmbus_g_connection.monitor_page_2, M_DEVBUF);
if (msg_info) {
sema_destroy(&msg_info->wait_sema);
free(msg_info, M_DEVBUF);
@ -284,8 +243,6 @@ hv_vmbus_disconnect(void)
ret = hv_vmbus_post_message(&msg, sizeof(hv_vmbus_channel_unload));
free(hv_vmbus_g_connection.interrupt_page, M_DEVBUF);
mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock);
free(hv_vmbus_g_connection.channels, M_DEVBUF);
@ -346,14 +303,13 @@ vmbus_event_proc(struct vmbus_softc *sc, int cpu)
}
void
vmbus_event_proc_compat(struct vmbus_softc *sc __unused, int cpu)
vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu)
{
struct vmbus_evtflags *eventf;
eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) {
vmbus_event_flags_proc(
hv_vmbus_g_connection.recv_interrupt_page,
vmbus_event_flags_proc(sc->vmbus_rx_evtflags,
VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT);
}
}
@ -376,8 +332,8 @@ int hv_vmbus_post_message(void *buffer, size_t bufferLen)
* insufficient resources. 20 times should suffice in practice.
*/
for (retries = 0; retries < 20; retries++) {
ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer,
bufferLen);
ret = hv_vmbus_post_msg_via_msg_ipc(connId,
VMBUS_MSGTYPE_CHANNEL, buffer, bufferLen);
if (ret == HV_STATUS_SUCCESS)
return (0);
@ -398,14 +354,12 @@ int hv_vmbus_post_message(void *buffer, size_t bufferLen)
int
hv_vmbus_set_event(hv_vmbus_channel *channel)
{
struct vmbus_softc *sc = vmbus_get_softc();
int ret = 0;
uint32_t child_rel_id = channel->offer_msg.child_rel_id;
uint32_t chanid = channel->offer_msg.child_rel_id;
/* Each uint32_t represents 32 channels */
synch_set_bit(child_rel_id & 31,
(((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
+ (child_rel_id >> 5))));
atomic_set_long(&sc->vmbus_tx_evtflags[chanid >> VMBUS_EVTFLAG_SHIFT],
1UL << (chanid & VMBUS_EVTFLAG_MASK));
ret = hv_vmbus_signal_event(channel->signal_event_param);
return (ret);

View File

@ -244,25 +244,7 @@ typedef enum {
typedef struct {
hv_vmbus_connect_state connect_state;
uint32_t next_gpadl_handle;
/**
* Represents channel interrupts. Each bit position
* represents a channel.
* When a channel sends an interrupt via VMBUS, it
* finds its bit in the send_interrupt_page, set it and
* calls Hv to generate a port event. The other end
* receives the port event and parse the
* recv_interrupt_page to see which bit is set
*/
void *interrupt_page;
void *send_interrupt_page;
void *recv_interrupt_page;
/*
* 2 pages - 1st page for parent->child
* notification and 2nd is child->parent
* notification
*/
void *monitor_page_1;
void *monitor_page_2;
TAILQ_HEAD(, hv_vmbus_channel_msg_info) channel_msg_anchor;
struct mtx channel_msg_lock;
/**
@ -364,16 +346,6 @@ typedef enum {
extern hv_vmbus_connection hv_vmbus_g_connection;
typedef void (*vmbus_msg_handler)(hv_vmbus_channel_msg_header *msg);
typedef struct hv_vmbus_channel_msg_table_entry {
hv_vmbus_channel_msg_type messageType;
vmbus_msg_handler messageHandler;
} hv_vmbus_channel_msg_table_entry;
extern hv_vmbus_channel_msg_table_entry g_channel_message_table[];
/*
* Private, VM Bus functions
*/
@ -450,7 +422,8 @@ int hv_vmbus_child_device_unregister(
/**
* Connection interfaces
*/
int hv_vmbus_connect(void);
struct vmbus_softc;
int hv_vmbus_connect(struct vmbus_softc *);
int hv_vmbus_disconnect(void);
int hv_vmbus_post_message(void *buffer, size_t buf_size);
int hv_vmbus_set_event(hv_vmbus_channel *channel);

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <dev/hyperv/include/hyperv_busdma.h>
#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
#include <dev/hyperv/vmbus/hyperv_machdep.h>
#include <dev/hyperv/vmbus/hyperv_reg.h>
#include <dev/hyperv/vmbus/hyperv_var.h>
#include <dev/hyperv/vmbus/vmbus_var.h>
@ -104,40 +105,17 @@ hyperv_get_timecount(struct timecounter *tc __unused)
* @brief Invoke the specified hypercall
*/
static uint64_t
hv_vmbus_do_hypercall(uint64_t control, void* input, void* output)
hv_vmbus_do_hypercall(uint64_t value, void *input, void *output)
{
#ifdef __x86_64__
uint64_t hv_status = 0;
uint64_t input_address = (input) ? hv_get_phys_addr(input) : 0;
uint64_t output_address = (output) ? hv_get_phys_addr(output) : 0;
volatile void *hypercall_page = hypercall_context.hc_addr;
uint64_t in_paddr = 0, out_paddr = 0;
__asm__ __volatile__ ("mov %0, %%r8" : : "r" (output_address): "r8");
__asm__ __volatile__ ("call *%3" : "=a"(hv_status):
"c" (control), "d" (input_address),
"m" (hypercall_page));
return (hv_status);
#else
uint32_t control_high = control >> 32;
uint32_t control_low = control & 0xFFFFFFFF;
uint32_t hv_status_high = 1;
uint32_t hv_status_low = 1;
uint64_t input_address = (input) ? hv_get_phys_addr(input) : 0;
uint32_t input_address_high = input_address >> 32;
uint32_t input_address_low = input_address & 0xFFFFFFFF;
uint64_t output_address = (output) ? hv_get_phys_addr(output) : 0;
uint32_t output_address_high = output_address >> 32;
uint32_t output_address_low = output_address & 0xFFFFFFFF;
volatile void *hypercall_page = hypercall_context.hc_addr;
if (input != NULL)
in_paddr = hv_get_phys_addr(input);
if (output != NULL)
out_paddr = hv_get_phys_addr(output);
__asm__ __volatile__ ("call *%8" : "=d"(hv_status_high),
"=a"(hv_status_low) : "d" (control_high),
"a" (control_low), "b" (input_address_high),
"c" (input_address_low),
"D"(output_address_high),
"S"(output_address_low), "m" (hypercall_page));
return (hv_status_low | ((uint64_t)hv_status_high << 32));
#endif /* __x86_64__ */
return hypercall_md(hypercall_context.hc_addr, value,
in_paddr, out_paddr);
}
/**

View File

@ -0,0 +1,37 @@
/*-
* Copyright (c) 2016 Microsoft Corp.
* 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.
*
* $FreeBSD$
*/
#ifndef _HYPERV_MACHDEP_H_
#define _HYPERV_MACHDEP_H_
#include <sys/param.h>
uint64_t hypercall_md(volatile void *hc_addr, uint64_t in_val,
uint64_t in_paddr, uint64_t out_paddr);
#endif /* !_HYPERV_MACHDEP_H_ */

View File

@ -0,0 +1,51 @@
/*-
* Copyright (c) 2016 Microsoft Corp.
* 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/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <dev/hyperv/vmbus/hyperv_machdep.h>
uint64_t
hypercall_md(volatile void *hc_addr, uint64_t in_val,
uint64_t in_paddr, uint64_t out_paddr)
{
uint32_t in_val_hi = in_val >> 32;
uint32_t in_val_lo = in_val & 0xFFFFFFFF;
uint32_t status_hi, status_lo;
uint32_t in_paddr_hi = in_paddr >> 32;
uint32_t in_paddr_lo = in_paddr & 0xFFFFFFFF;
uint32_t out_paddr_hi = out_paddr >> 32;
uint32_t out_paddr_lo = out_paddr & 0xFFFFFFFF;
__asm__ __volatile__ ("call *%8" : "=d"(status_hi), "=a"(status_lo) :
"d" (in_val_hi), "a" (in_val_lo),
"b" (in_paddr_hi), "c" (in_paddr_lo),
"D"(out_paddr_hi), "S"(out_paddr_lo),
"m" (hc_addr));
return (status_lo | ((uint64_t)status_hi << 32));
}

View File

@ -81,27 +81,15 @@ vmbus_msg_task(void *xsc, int pending __unused)
msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
for (;;) {
const hv_vmbus_channel_msg_table_entry *entry;
hv_vmbus_channel_msg_header *hdr;
hv_vmbus_channel_msg_type msg_type;
if (msg->msg_type == VMBUS_MSGTYPE_NONE)
break; /* no message */
/* XXX: update messageHandler interface */
hdr = __DEVOLATILE(hv_vmbus_channel_msg_header *,
msg->msg_data);
msg_type = hdr->message_type;
if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
printf("VMBUS: unknown message type = %d\n", msg_type);
goto handled;
if (msg->msg_type == VMBUS_MSGTYPE_NONE) {
/* No message */
break;
} else if (msg->msg_type == VMBUS_MSGTYPE_CHANNEL) {
/* Channel message */
vmbus_chan_msgproc(sc,
__DEVOLATILE(const struct vmbus_message *, msg));
}
entry = &g_channel_message_table[msg_type];
if (entry->messageHandler)
entry->messageHandler(hdr);
handled:
msg->msg_type = VMBUS_MSGTYPE_NONE;
/*
* Make sure the write to msg_type (i.e. set to
@ -321,30 +309,50 @@ vmbus_synic_teardown(void *arg)
static int
vmbus_dma_alloc(struct vmbus_softc *sc)
{
bus_dma_tag_t parent_dtag;
uint8_t *evtflags;
int cpu;
parent_dtag = bus_get_dma_tag(sc->vmbus_dev);
CPU_FOREACH(cpu) {
void *ptr;
/*
* Per-cpu messages and event flags.
*/
ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
PAGE_SIZE, 0, PAGE_SIZE,
VMBUS_PCPU_PTR(sc, message_dma, cpu),
ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
PAGE_SIZE, VMBUS_PCPU_PTR(sc, message_dma, cpu),
BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (ptr == NULL)
return ENOMEM;
VMBUS_PCPU_GET(sc, message, cpu) = ptr;
ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
PAGE_SIZE, 0, PAGE_SIZE,
VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
PAGE_SIZE, VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (ptr == NULL)
return ENOMEM;
VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr;
}
evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (evtflags == NULL)
return ENOMEM;
sc->vmbus_rx_evtflags = (u_long *)evtflags;
sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2));
sc->vmbus_evtflags = evtflags;
sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (sc->vmbus_mnf1 == NULL)
return ENOMEM;
sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
PAGE_SIZE, &sc->vmbus_mnf2_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (sc->vmbus_mnf2 == NULL)
return ENOMEM;
return 0;
}
@ -353,6 +361,21 @@ vmbus_dma_free(struct vmbus_softc *sc)
{
int cpu;
if (sc->vmbus_evtflags != NULL) {
hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags);
sc->vmbus_evtflags = NULL;
sc->vmbus_rx_evtflags = NULL;
sc->vmbus_tx_evtflags = NULL;
}
if (sc->vmbus_mnf1 != NULL) {
hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1);
sc->vmbus_mnf1 = NULL;
}
if (sc->vmbus_mnf2 != NULL) {
hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2);
sc->vmbus_mnf2 = NULL;
}
CPU_FOREACH(cpu) {
if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
hyperv_dmamem_free(
@ -701,8 +724,7 @@ vmbus_bus_init(void)
/*
* Connect to VMBus in the root partition
*/
ret = hv_vmbus_connect();
ret = hv_vmbus_connect(sc);
if (ret != 0)
goto cleanup;

View File

@ -49,6 +49,7 @@ struct vmbus_message {
CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
#define VMBUS_MSGTYPE_NONE 0
#define VMBUS_MSGTYPE_CHANNEL 1
#define VMBUS_MSGTYPE_TIMER_EXPIRED 0x80000010
#define VMBUS_MSGFLAG_PENDING 0x01
@ -65,6 +66,7 @@ CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
#define VMBUS_EVTFLAG_SHIFT 5
#endif
#define VMBUS_EVTFLAG_LEN (1 << VMBUS_EVTFLAG_SHIFT)
#define VMBUS_EVTFLAG_MASK (VMBUS_EVTFLAG_LEN - 1)
#define VMBUS_EVTFLAGS_SIZE 256
struct vmbus_evtflags {

View File

@ -50,7 +50,7 @@ struct vmbus_pcpu_data {
struct vmbus_message *message; /* shared messages */
uint32_t vcpuid; /* virtual cpuid */
int event_flags_cnt;/* # of event flags */
struct vmbus_evtflags *event_flags; /* shared event flags */
struct vmbus_evtflags *event_flags; /* event flags from host */
/* Rarely used fields */
struct hyperv_dma message_dma; /* busdma glue */
@ -62,12 +62,26 @@ struct vmbus_pcpu_data {
struct vmbus_softc {
void (*vmbus_event_proc)(struct vmbus_softc *, int);
u_long *vmbus_tx_evtflags;
/* event flags to host */
void *vmbus_mnf2; /* monitored by host */
u_long *vmbus_rx_evtflags;
/* compat evtflgs from host */
struct vmbus_pcpu_data vmbus_pcpu[MAXCPU];
/* Rarely used fields */
device_t vmbus_dev;
int vmbus_idtvec;
uint32_t vmbus_flags; /* see VMBUS_FLAG_ */
/* Shared memory for vmbus_{rx,tx}_evtflags */
void *vmbus_evtflags;
struct hyperv_dma vmbus_evtflags_dma;
void *vmbus_mnf1; /* monitored by VM, unused */
struct hyperv_dma vmbus_mnf1_dma;
struct hyperv_dma vmbus_mnf2_dma;
};
#define VMBUS_FLAG_ATTACHED 0x0001 /* vmbus was attached */
@ -92,6 +106,7 @@ vmbus_get_device(void)
struct hv_vmbus_channel;
struct trapframe;
struct vmbus_message;
void vmbus_on_channel_open(const struct hv_vmbus_channel *);
void vmbus_event_proc(struct vmbus_softc *, int);
@ -100,4 +115,6 @@ void vmbus_handle_intr(struct trapframe *);
void vmbus_et_intr(struct trapframe *);
void vmbus_chan_msgproc(struct vmbus_softc *, const struct vmbus_message *);
#endif /* !_VMBUS_VAR_H_ */

View File

@ -10,6 +10,7 @@ SRCS= hv_channel.c \
hv_ring_buffer.c \
hyperv.c \
hyperv_busdma.c \
hyperv_machdep.c \
vmbus.c \
vmbus_et.c
SRCS+= acpi_if.h bus_if.h device_if.h opt_acpi.h