summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/vmbus/hv_channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hyperv/vmbus/hv_channel.c')
-rw-r--r--sys/dev/hyperv/vmbus/hv_channel.c150
1 files changed, 113 insertions, 37 deletions
diff --git a/sys/dev/hyperv/vmbus/hv_channel.c b/sys/dev/hyperv/vmbus/hv_channel.c
index bb777cc..6da0643 100644
--- a/sys/dev/hyperv/vmbus/hv_channel.c
+++ b/sys/dev/hyperv/vmbus/hv_channel.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009-2012 Microsoft Corp.
+ * Copyright (c) 2009-2012,2016 Microsoft Corp.
* Copyright (c) 2012 NetApp Inc.
* Copyright (c) 2012 Citrix Inc.
* All rights reserved.
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sysctl.h>
#include <machine/bus.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -80,6 +81,90 @@ vmbus_channel_set_event(hv_vmbus_channel *channel)
}
+static int
+vmbus_channel_sysctl_monalloc(SYSCTL_HANDLER_ARGS)
+{
+ struct hv_vmbus_channel *chan = arg1;
+ int alloc = 0;
+
+ if (chan->offer_msg.monitor_allocated)
+ alloc = 1;
+ return sysctl_handle_int(oidp, &alloc, 0, req);
+}
+
+static void
+vmbus_channel_sysctl_create(hv_vmbus_channel* channel)
+{
+ device_t dev;
+ struct sysctl_oid *devch_sysctl;
+ struct sysctl_oid *devch_id_sysctl, *devch_sub_sysctl;
+ struct sysctl_oid *devch_id_in_sysctl, *devch_id_out_sysctl;
+ struct sysctl_ctx_list *ctx;
+ uint32_t ch_id;
+ uint16_t sub_ch_id;
+ char name[16];
+
+ hv_vmbus_channel* primary_ch = channel->primary_channel;
+
+ if (primary_ch == NULL) {
+ dev = channel->device->device;
+ ch_id = channel->offer_msg.child_rel_id;
+ } else {
+ dev = primary_ch->device->device;
+ ch_id = primary_ch->offer_msg.child_rel_id;
+ sub_ch_id = channel->offer_msg.offer.sub_channel_index;
+ }
+ ctx = device_get_sysctl_ctx(dev);
+ /* This creates dev.DEVNAME.DEVUNIT.channel tree */
+ devch_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "channel", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+ /* This creates dev.DEVNAME.DEVUNIT.channel.CHANID tree */
+ snprintf(name, sizeof(name), "%d", ch_id);
+ devch_id_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(devch_sysctl),
+ OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+
+ if (primary_ch != NULL) {
+ devch_sub_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(devch_id_sysctl),
+ OID_AUTO, "sub", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+ snprintf(name, sizeof(name), "%d", sub_ch_id);
+ devch_id_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(devch_sub_sysctl),
+ OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(devch_id_sysctl),
+ OID_AUTO, "chanid", CTLFLAG_RD,
+ &channel->offer_msg.child_rel_id, 0, "channel id");
+ }
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(devch_id_sysctl), OID_AUTO,
+ "cpu", CTLFLAG_RD, &channel->target_cpu, 0, "owner CPU id");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(devch_id_sysctl), OID_AUTO,
+ "monitor_allocated", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ channel, 0, vmbus_channel_sysctl_monalloc, "I",
+ "is monitor allocated to this channel");
+
+ devch_id_in_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(devch_id_sysctl),
+ OID_AUTO,
+ "in",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+ devch_id_out_sysctl = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(devch_id_sysctl),
+ OID_AUTO,
+ "out",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
+ hv_ring_buffer_stat(ctx,
+ SYSCTL_CHILDREN(devch_id_in_sysctl),
+ &(channel->inbound),
+ "inbound ring buffer stats");
+ hv_ring_buffer_stat(ctx,
+ SYSCTL_CHILDREN(devch_id_out_sysctl),
+ &(channel->outbound),
+ "outbound ring buffer stats");
+}
+
/**
* @brief Open the specified channel
*/
@@ -143,6 +228,9 @@ hv_vmbus_channel_open(
in,
recv_ring_buffer_size);
+ /* Create sysctl tree for this channel */
+ vmbus_channel_sysctl_create(new_channel);
+
/**
* Establish the gpadl for the ring buffer
*/
@@ -182,12 +270,12 @@ hv_vmbus_channel_open(
if (user_data_len)
memcpy(open_msg->user_data, user_data, user_data_len);
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(
&hv_vmbus_g_connection.channel_msg_anchor,
open_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(
open_msg, sizeof(hv_vmbus_channel_open_channel));
@@ -214,12 +302,12 @@ hv_vmbus_channel_open(
}
cleanup:
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(
&hv_vmbus_g_connection.channel_msg_anchor,
open_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&open_info->wait_sema);
free(open_info, M_DEVBUF);
@@ -384,17 +472,22 @@ hv_vmbus_channel_establish_gpadl(
hv_vmbus_channel_msg_info* curr;
uint32_t next_gpadl_handle;
- next_gpadl_handle = hv_vmbus_g_connection.next_gpadl_handle;
- atomic_add_int((int*) &hv_vmbus_g_connection.next_gpadl_handle, 1);
+ next_gpadl_handle = atomic_fetchadd_int(
+ &hv_vmbus_g_connection.next_gpadl_handle, 1);
ret = vmbus_channel_create_gpadl_header(
contig_buffer, size, &msg_info, &msg_count);
- if(ret != 0) { /* if(allocation failed) return immediately */
- /* reverse atomic_add_int above */
- atomic_subtract_int((int*)
- &hv_vmbus_g_connection.next_gpadl_handle, 1);
- return ret;
+ if(ret != 0) {
+ /*
+ * XXX
+ * We can _not_ even revert the above incremental,
+ * if multiple GPADL establishments are running
+ * parallelly, decrement the global next_gpadl_handle
+ * is calling for _big_ trouble. A better solution
+ * is to have a 0-based GPADL id bitmap ...
+ */
+ return ret;
}
sema_init(&msg_info->wait_sema, 0, "Open Info Sema");
@@ -403,13 +496,13 @@ hv_vmbus_channel_establish_gpadl(
gpadl_msg->child_rel_id = channel->offer_msg.child_rel_id;
gpadl_msg->gpadl = next_gpadl_handle;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(
&hv_vmbus_g_connection.channel_msg_anchor,
msg_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(
gpadl_msg,
@@ -448,10 +541,10 @@ hv_vmbus_channel_establish_gpadl(
cleanup:
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor,
msg_info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&msg_info->wait_sema);
free(msg_info, M_DEVBUF);
@@ -490,10 +583,10 @@ hv_vmbus_channel_teardown_gpdal(
msg->child_rel_id = channel->offer_msg.child_rel_id;
msg->gpadl = gpadl_handle;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_msg_anchor,
info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(msg,
sizeof(hv_vmbus_channel_gpadl_teardown));
@@ -506,10 +599,10 @@ cleanup:
/*
* Received a torndown response
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor,
info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&info->wait_sema);
free(info, M_DEVBUF);
@@ -525,20 +618,13 @@ hv_vmbus_channel_close_internal(hv_vmbus_channel *channel)
hv_vmbus_channel_msg_info* info;
channel->state = HV_CHANNEL_OPEN_STATE;
- 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
- * and unloading driver is in the process.
- */
- mtx_lock(&channel->inbound_lock);
channel->on_channel_callback = NULL;
- mtx_unlock(&channel->inbound_lock);
/**
* Send a closing message
@@ -857,7 +943,6 @@ hv_vmbus_channel_recv_packet_raw(
{
int ret;
uint32_t packetLen;
- uint32_t userLen;
hv_vm_packet_descriptor desc;
*buffer_actual_len = 0;
@@ -871,8 +956,6 @@ hv_vmbus_channel_recv_packet_raw(
return (0);
packetLen = desc.length8 << 3;
- userLen = packetLen - (desc.data_offset8 << 3);
-
*buffer_actual_len = packetLen;
if (packetLen > buffer_len)
@@ -915,12 +998,6 @@ VmbusProcessChannelEvent(void* context, int pending)
* 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;
@@ -947,5 +1024,4 @@ VmbusProcessChannelEvent(void* context, int pending)
bytes_to_read = 0;
} while (is_batched_reading && (bytes_to_read != 0));
}
- // mtx_unlock(&channel->inbound_lock);
}
OpenPOWER on IntegriCloud