Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/vmbus/hv_channel.c
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | static int vmbus_channel_create_gpadl_header( | ||||
/* must be phys and virt contiguous*/ | /* must be phys and virt contiguous*/ | ||||
void* contig_buffer, | void* contig_buffer, | ||||
/* page-size multiple */ | /* page-size multiple */ | ||||
uint32_t size, | uint32_t size, | ||||
hv_vmbus_channel_msg_info** msg_info, | hv_vmbus_channel_msg_info** msg_info, | ||||
uint32_t* message_count); | uint32_t* message_count); | ||||
static void vmbus_channel_set_event(hv_vmbus_channel* channel); | static void vmbus_channel_set_event(hv_vmbus_channel* channel); | ||||
static void VmbusProcessChannelEvent(void* channel, int pending); | |||||
/** | /** | ||||
* @brief Trigger an event notification on the specified channel | * @brief Trigger an event notification on the specified channel | ||||
*/ | */ | ||||
static void | static void | ||||
vmbus_channel_set_event(hv_vmbus_channel *channel) | vmbus_channel_set_event(hv_vmbus_channel *channel) | ||||
{ | { | ||||
hv_vmbus_monitor_page *monitor_page; | hv_vmbus_monitor_page *monitor_page; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | printf("VMBUS: Trying to open channel <%p> which in " | ||||
"%d state.\n", new_channel, new_channel->state); | "%d state.\n", new_channel, new_channel->state); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
mtx_unlock(&new_channel->sc_lock); | mtx_unlock(&new_channel->sc_lock); | ||||
new_channel->on_channel_callback = pfn_on_channel_callback; | new_channel->on_channel_callback = pfn_on_channel_callback; | ||||
new_channel->channel_callback_context = context; | new_channel->channel_callback_context = context; | ||||
new_channel->rxq = hv_vmbus_g_context.hv_event_queue[new_channel->target_cpu]; | |||||
TASK_INIT(&new_channel->channel_task, 0, VmbusProcessChannelEvent, new_channel); | |||||
/* Allocate the ring buffer */ | /* Allocate the ring buffer */ | ||||
out = contigmalloc((send_ring_buffer_size + recv_ring_buffer_size), | out = contigmalloc((send_ring_buffer_size + recv_ring_buffer_size), | ||||
M_DEVBUF, M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); | M_DEVBUF, M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); | ||||
KASSERT(out != NULL, | KASSERT(out != NULL, | ||||
("Error VMBUS: contigmalloc failed to allocate Ring Buffer!")); | ("Error VMBUS: contigmalloc failed to allocate Ring Buffer!")); | ||||
if (out == NULL) | if (out == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
▲ Show 20 Lines • Show All 387 Lines • ▼ Show 20 Lines | cleanup: | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static void | static void | ||||
hv_vmbus_channel_close_internal(hv_vmbus_channel *channel) | hv_vmbus_channel_close_internal(hv_vmbus_channel *channel) | ||||
{ | { | ||||
int ret = 0; | int ret = 0; | ||||
struct taskqueue *rxq = channel->rxq; | |||||
hv_vmbus_channel_close_channel* msg; | hv_vmbus_channel_close_channel* msg; | ||||
hv_vmbus_channel_msg_info* info; | hv_vmbus_channel_msg_info* info; | ||||
channel->state = HV_CHANNEL_OPEN_STATE; | channel->state = HV_CHANNEL_OPEN_STATE; | ||||
channel->sc_creation_callback = NULL; | channel->sc_creation_callback = NULL; | ||||
/* | /* | ||||
* set rxq to NULL to avoid more requests be scheduled | |||||
*/ | |||||
channel->rxq = NULL; | |||||
taskqueue_drain(rxq, &channel->channel_task); | |||||
/* | |||||
* Grab the lock to prevent race condition when a packet received | * Grab the lock to prevent race condition when a packet received | ||||
* and unloading driver is in the process. | * and unloading driver is in the process. | ||||
*/ | */ | ||||
mtx_lock(&channel->inbound_lock); | mtx_lock(&channel->inbound_lock); | ||||
channel->on_channel_callback = NULL; | channel->on_channel_callback = NULL; | ||||
mtx_unlock(&channel->inbound_lock); | mtx_unlock(&channel->inbound_lock); | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 335 Lines • ▼ Show 20 Lines | if (packetLen > buffer_len) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
*request_id = desc.transaction_id; | *request_id = desc.transaction_id; | ||||
/* Copy over the entire packet to the user buffer */ | /* Copy over the entire packet to the user buffer */ | ||||
ret = hv_ring_buffer_read(&channel->inbound, buffer, packetLen, 0); | ret = hv_ring_buffer_read(&channel->inbound, buffer, packetLen, 0); | ||||
return (0); | return (0); | ||||
} | |||||
/** | |||||
* Process a channel event notification | |||||
*/ | |||||
static void | |||||
VmbusProcessChannelEvent(void* context, int pending) | |||||
{ | |||||
void* arg; | |||||
uint32_t bytes_to_read; | |||||
hv_vmbus_channel* channel = (hv_vmbus_channel*)context; | |||||
boolean_t is_batched_reading; | |||||
/** | |||||
* Find the channel based on this relid and invokes | |||||
* the channel callback to process the event | |||||
*/ | |||||
if (channel == NULL) { | |||||
return; | |||||
} | |||||
/** | |||||
* To deal with the race condition where we might | |||||
* receive a packet while the relevant driver is | |||||
* being unloaded, dispatch the callback while | |||||
* holding the channel lock. The unloading driver | |||||
* will acquire the same channel lock to set the | |||||
* callback to NULL. This closes the window. | |||||
*/ | |||||
/* | |||||
* Disable the lock due to newly added WITNESS check in r277723. | |||||
* Will seek other way to avoid race condition. | |||||
* -- whu | |||||
*/ | |||||
// mtx_lock(&channel->inbound_lock); | |||||
if (channel->on_channel_callback != NULL) { | |||||
arg = channel->channel_callback_context; | |||||
is_batched_reading = channel->batched_reading; | |||||
/* | |||||
* Optimize host to guest signaling by ensuring: | |||||
* 1. While reading the channel, we disable interrupts from | |||||
* host. | |||||
* 2. Ensure that we process all posted messages from the host | |||||
* before returning from this callback. | |||||
* 3. Once we return, enable signaling from the host. Once this | |||||
* state is set we check to see if additional packets are | |||||
* available to read. In this case we repeat the process. | |||||
*/ | |||||
do { | |||||
if (is_batched_reading) | |||||
hv_ring_buffer_read_begin(&channel->inbound); | |||||
channel->on_channel_callback(arg); | |||||
if (is_batched_reading) | |||||
bytes_to_read = | |||||
hv_ring_buffer_read_end(&channel->inbound); | |||||
else | |||||
bytes_to_read = 0; | |||||
} while (is_batched_reading && (bytes_to_read != 0)); | |||||
} | |||||
// mtx_unlock(&channel->inbound_lock); | |||||
} | } |