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:
Sepherosa Ziehau 2016-06-08 05:34:22 +00:00
parent 4af86fb4f9
commit 6523ab7e00
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=301583
5 changed files with 76 additions and 90 deletions

View File

@ -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);

View File

@ -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);

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;
/**
@ -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);

View File

@ -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;

View File

@ -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 */