Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Jan 2016 07:29:31 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r294553 - head/sys/dev/hyperv/vmbus
Message-ID:  <201601220729.u0M7TVA5065629@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Jan 22 07:29:31 2016
New Revision: 294553
URL: https://svnweb.freebsd.org/changeset/base/294553

Log:
  hyperv/vmbus: Lookup channel through id table
  
  Vmbus event handler will need to find the channel by its relative
  id, when software interrupt for event happens.  The original lookup
  searches the channel list, which is not very efficient.  We now
  create a table indexed by the channel relative id to speed up
  the channel lookup.
  
  Submitted by:		Hongjiang Zhang <honzhan microsoft com>
  Reviewed by:		delphij, adrain, sephe, Dexuan Cui <decui microsoft com>
  Approved by:		adrian (mentor)
  Sponsored by:		Microsoft OSTC
  Differential Revision:	https://reviews.freebsd.org/D4802

Modified:
  head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
  head/sys/dev/hyperv/vmbus/hv_connection.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h

Modified: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Fri Jan 22 07:25:59 2016	(r294552)
+++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Fri Jan 22 07:29:31 2016	(r294553)
@@ -271,14 +271,16 @@ vmbus_channel_process_offer(hv_vmbus_cha
 	boolean_t		f_new;
 	hv_vmbus_channel*	channel;
 	int			ret;
+	uint32_t                relid;
 
 	f_new = TRUE;
 	channel = NULL;
-
+	relid = new_channel->offer_msg.child_rel_id;
 	/*
 	 * Make sure this is a new offer
 	 */
 	mtx_lock(&hv_vmbus_g_connection.channel_lock);
+	hv_vmbus_g_connection.channels[relid] = new_channel;
 
 	TAILQ_FOREACH(channel, &hv_vmbus_g_connection.channel_anchor,
 	    list_entry)
@@ -322,16 +324,18 @@ vmbus_channel_process_offer(hv_vmbus_cha
 			mtx_unlock(&channel->sc_lock);
 
 			/* Insert new channel into channel_anchor. */
-			printf("Storvsc get multi-channel offer, rel=%u.\n",
-			    new_channel->offer_msg.child_rel_id);	
+			printf("VMBUS get multi-channel offer, rel=%u,sub=%u\n",
+			    new_channel->offer_msg.child_rel_id,
+			    new_channel->offer_msg.offer.sub_channel_index);	
 			mtx_lock(&hv_vmbus_g_connection.channel_lock);
 			TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_anchor,
 			    new_channel, list_entry);				
 			mtx_unlock(&hv_vmbus_g_connection.channel_lock);
 
 			if(bootverbose)
-				printf("VMBUS: new multi-channel offer <%p>.\n",
-				    new_channel);
+				printf("VMBUS: new multi-channel offer <%p>, "
+				    "its primary channel is <%p>.\n",
+				    new_channel, new_channel->primary_channel);
 
 			/*XXX add it to percpu_list */
 
@@ -521,11 +525,14 @@ vmbus_channel_on_offer_rescind(hv_vmbus_
 
 	rescind = (hv_vmbus_channel_rescind_offer*) hdr;
 
-	channel = hv_vmbus_get_channel_from_rel_id(rescind->child_rel_id);
+	channel = hv_vmbus_g_connection.channels[rescind->child_rel_id];
 	if (channel == NULL) 
 	    return;
 
 	hv_vmbus_child_device_unregister(channel->device);
+	mtx_lock(&hv_vmbus_g_connection.channel_lock);
+	hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL;
+	mtx_unlock(&hv_vmbus_g_connection.channel_lock);
 }
 
 /**
@@ -779,6 +786,8 @@ hv_vmbus_release_unattached_channels(voi
 	    hv_vmbus_child_device_unregister(channel->device);
 	    hv_vmbus_free_vmbus_channel(channel);
 	}
+	bzero(hv_vmbus_g_connection.channels, 
+		sizeof(hv_vmbus_channel*) * HV_CHANNEL_MAX_COUNT);
 	mtx_unlock(&hv_vmbus_g_connection.channel_lock);
 }
 

Modified: head/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_connection.c	Fri Jan 22 07:25:59 2016	(r294552)
+++ head/sys/dev/hyperv/vmbus/hv_connection.c	Fri Jan 22 07:29:31 2016	(r294553)
@@ -229,6 +229,9 @@ hv_vmbus_connect(void) {
 	    goto cleanup;
 	}
 
+	hv_vmbus_g_connection.channels = malloc(sizeof(hv_vmbus_channel*) *
+		HV_CHANNEL_MAX_COUNT,
+		M_DEVBUF, M_WAITOK | M_ZERO);
 	/*
 	 * Find the highest vmbus version number we can support.
 	 */
@@ -292,6 +295,7 @@ hv_vmbus_connect(void) {
 		free(msg_info, M_DEVBUF);
 	}
 
+	free(hv_vmbus_g_connection.channels, M_DEVBUF);
 	return (ret);
 }
 
@@ -322,6 +326,7 @@ hv_vmbus_disconnect(void) {
 	hv_work_queue_close(hv_vmbus_g_connection.work_queue);
 	sema_destroy(&hv_vmbus_g_connection.control_sema);
 
+	free(hv_vmbus_g_connection.channels, M_DEVBUF);
 	hv_vmbus_g_connection.connect_state = HV_DISCONNECTED;
 
 	free(msg, M_DEVBUF);
@@ -330,35 +335,6 @@ hv_vmbus_disconnect(void) {
 }
 
 /**
- * Get the channel object given its child relative id (ie channel id)
- */
-hv_vmbus_channel*
-hv_vmbus_get_channel_from_rel_id(uint32_t rel_id) {
-
-	hv_vmbus_channel* channel;
-	hv_vmbus_channel* foundChannel = NULL;
-
-	/*
-	 * TODO:
-	 * Consider optimization where relids are stored in a fixed size array
-	 *  and channels are accessed without the need to take this lock or search
-	 *  the list.
-	 */
-	mtx_lock(&hv_vmbus_g_connection.channel_lock);
-	TAILQ_FOREACH(channel,
-		&hv_vmbus_g_connection.channel_anchor, list_entry) {
-
-	    if (channel->offer_msg.child_rel_id == rel_id) {
-		foundChannel = channel;
-		break;
-	    }
-	}
-	mtx_unlock(&hv_vmbus_g_connection.channel_lock);
-
-	return (foundChannel);
-}
-
-/**
  * Process a channel event notification
  */
 static void
@@ -374,7 +350,7 @@ VmbusProcessChannelEvent(uint32_t relid)
 	 * the channel callback to process the event
 	 */
 
-	channel = hv_vmbus_get_channel_from_rel_id(relid);
+	channel = hv_vmbus_g_connection.channels[relid];
 
 	if (channel == NULL) {
 		return;
@@ -470,7 +446,7 @@ hv_vmbus_on_events(void *arg) 
 	if (recv_interrupt_page != NULL) {
 	    for (dword = 0; dword < maxdword; dword++) {
 		if (recv_interrupt_page[dword]) {
-		    for (bit = 0; bit < 32; bit++) {
+		    for (bit = 0; bit < HV_CHANNEL_DWORD_LEN; bit++) {
 			if (synch_test_and_clear_bit(bit,
 			    (uint32_t *) &recv_interrupt_page[dword])) {
 			    rel_id = (dword << 5) + bit;

Modified: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Fri Jan 22 07:25:59 2016	(r294552)
+++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Fri Jan 22 07:29:31 2016	(r294553)
@@ -58,6 +58,12 @@ typedef uint16_t hv_vmbus_status;
 #define HV_EVENT_FLAGS_BYTE_COUNT   (256)
 #define HV_EVENT_FLAGS_DWORD_COUNT  (256 / sizeof(uint32_t))
 
+/**
+ * max channel count <== event_flags_dword_count * bit_of_dword
+ */
+#define HV_CHANNEL_DWORD_LEN        (32)
+#define HV_CHANNEL_MAX_COUNT        \
+	((HV_EVENT_FLAGS_DWORD_COUNT) * HV_CHANNEL_DWORD_LEN)
 /*
  * MessageId: HV_STATUS_INSUFFICIENT_BUFFERS
  * MessageText:
@@ -355,6 +361,10 @@ typedef struct {
 	TAILQ_HEAD(, hv_vmbus_channel)		channel_anchor;
 	struct mtx				channel_lock;
 
+	/**
+	 * channel table for fast lookup through id.
+	 */
+	hv_vmbus_channel                        **channels;
 	hv_vmbus_handle				work_queue;
 	struct sema				control_sema;
 } hv_vmbus_connection;
@@ -699,7 +709,6 @@ int			hv_vmbus_child_device_register(
 					struct hv_device *child_dev);
 int			hv_vmbus_child_device_unregister(
 					struct hv_device *child_dev);
-hv_vmbus_channel*	hv_vmbus_get_channel_from_rel_id(uint32_t rel_id);
 
 /**
  * Connection interfaces



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601220729.u0M7TVA5065629>