hyperv/vmbus: Busdma-fy MNF and event flags.
MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D6744
This commit is contained in:
parent
4af86fb4f9
commit
6523ab7e00
@ -62,17 +62,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) {
|
||||
struct vmbus_softc *sc = vmbus_get_softc();
|
||||
hv_vmbus_monitor_page *monitor_page;
|
||||
|
||||
/* 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
|
||||
((uint32_t *)sc->vmbus_tx_evtflags
|
||||
+ ((channel->offer_msg.child_rel_id >> 5))));
|
||||
|
||||
monitor_page = (hv_vmbus_monitor_page *)
|
||||
hv_vmbus_g_connection.monitor_page_2;
|
||||
|
||||
monitor_page = sc->vmbus_mnf2;
|
||||
synch_set_bit(channel->monitor_bit,
|
||||
(uint32_t *)&monitor_page->
|
||||
trigger_group[channel->monitor_group].u.pending);
|
||||
|
@ -74,8 +74,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;
|
||||
@ -86,14 +86,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
|
||||
@ -150,7 +145,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;
|
||||
@ -176,34 +171,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),
|
||||
@ -217,7 +184,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.
|
||||
@ -251,14 +218,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);
|
||||
@ -281,8 +240,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);
|
||||
@ -343,14 +300,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);
|
||||
}
|
||||
}
|
||||
@ -395,14 +351,14 @@ 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;
|
||||
|
||||
/* 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))));
|
||||
(((uint32_t *)sc->vmbus_tx_evtflags + (child_rel_id >> 5))));
|
||||
ret = hv_vmbus_signal_event(channel->signal_event_param);
|
||||
|
||||
return (ret);
|
||||
|
@ -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;
|
||||
/**
|
||||
@ -440,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);
|
||||
|
@ -309,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 = 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;
|
||||
}
|
||||
|
||||
@ -341,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(
|
||||
@ -609,8 +644,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;
|
||||
|
||||
|
@ -51,7 +51,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 */
|
||||
@ -63,12 +63,26 @@ struct vmbus_pcpu_data {
|
||||
|
||||
struct vmbus_softc {
|
||||
void (*vmbus_event_proc)(struct vmbus_softc *, int);
|
||||
void *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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user