svn commit: r303020 - in head/sys/dev/hyperv: include storvsc vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Tue Jul 19 05:46:17 UTC 2016


Author: sephe
Date: Tue Jul 19 05:46:15 2016
New Revision: 303020
URL: https://svnweb.freebsd.org/changeset/base/303020

Log:
  hyperv/vmbus: Cleanup cpu based channel selection.
  
  And create cpu to channel map at device attach time for storvsc(4).
  
  MFC after:	1 week
  Sponsored by:	Microsoft OSTC
  Differential Revision:	https://reviews.freebsd.org/D7229

Modified:
  head/sys/dev/hyperv/include/hyperv.h
  head/sys/dev/hyperv/include/vmbus.h
  head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
  head/sys/dev/hyperv/vmbus/hv_channel.c

Modified: head/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- head/sys/dev/hyperv/include/hyperv.h	Tue Jul 19 05:36:21 2016	(r303019)
+++ head/sys/dev/hyperv/include/hyperv.h	Tue Jul 19 05:46:15 2016	(r303020)
@@ -281,8 +281,6 @@ int		hv_vmbus_channel_open(struct hv_vmb
 		    vmbus_chan_callback_t cb, void *cbarg);
 void		hv_vmbus_channel_close(hv_vmbus_channel *channel);
 
-struct hv_vmbus_channel* vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary);
-
 /**
  * @brief Get physical address from virtual
  */

Modified: head/sys/dev/hyperv/include/vmbus.h
==============================================================================
--- head/sys/dev/hyperv/include/vmbus.h	Tue Jul 19 05:36:21 2016	(r303019)
+++ head/sys/dev/hyperv/include/vmbus.h	Tue Jul 19 05:46:15 2016	(r303020)
@@ -96,13 +96,14 @@ int	vmbus_chan_gpadl_disconnect(struct h
 
 void	vmbus_chan_cpu_set(struct hv_vmbus_channel *chan, int cpu);
 void	vmbus_chan_cpu_rr(struct hv_vmbus_channel *chan);
+struct hv_vmbus_channel *
+	vmbus_chan_cpu2chan(struct hv_vmbus_channel *chan, int cpu);
 
 struct hv_vmbus_channel **
 	vmbus_subchan_get(struct hv_vmbus_channel *pri_chan, int subchan_cnt);
 void	vmbus_subchan_rel(struct hv_vmbus_channel **subchan, int subchan_cnt);
 void	vmbus_subchan_drain(struct hv_vmbus_channel *pri_chan);
 
-
 int	vmbus_chan_recv(struct hv_vmbus_channel *chan, void *data, int *dlen,
 	    uint64_t *xactid);
 int	vmbus_chan_recv_pkt(struct hv_vmbus_channel *chan,

Modified: head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c	Tue Jul 19 05:36:21 2016	(r303019)
+++ head/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c	Tue Jul 19 05:46:15 2016	(r303020)
@@ -147,6 +147,8 @@ struct storvsc_softc {
 	struct hv_storvsc_request	hs_init_req;
 	struct hv_storvsc_request	hs_reset_req;
 	device_t			hs_dev;
+
+	struct hv_vmbus_channel		*hs_cpu2chan[MAXCPU];
 };
 
 
@@ -664,7 +666,7 @@ hv_storvsc_io_request(struct storvsc_sof
 
 	vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
 
-	outgoing_channel = vmbus_select_outgoing_channel(sc->hs_chan);
+	outgoing_channel = sc->hs_cpu2chan[curcpu];
 
 	mtx_unlock(&request->softc->hs_lock);
 	if (request->prp_list.gpa_range.gpa_len) {
@@ -870,6 +872,20 @@ storvsc_probe(device_t dev)
 	return (ret);
 }
 
+static void
+storvsc_create_cpu2chan(struct storvsc_softc *sc)
+{
+	int cpu;
+
+	CPU_FOREACH(cpu) {
+		sc->hs_cpu2chan[cpu] = vmbus_chan_cpu2chan(sc->hs_chan, cpu);
+		if (bootverbose) {
+			device_printf(sc->hs_dev, "cpu%d -> chan%u\n",
+			    cpu, sc->hs_cpu2chan[cpu]->ch_id);
+		}
+	}
+}
+
 /**
  * @brief StorVSC attach function
  *
@@ -967,6 +983,9 @@ storvsc_attach(device_t dev)
 		goto cleanup;
 	}
 
+	/* Construct cpu to channel mapping */
+	storvsc_create_cpu2chan(sc);
+
 	/*
 	 * Create the device queue.
 	 * Hyper-V maps each target to one SCSI HBA

Modified: head/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel.c	Tue Jul 19 05:36:21 2016	(r303019)
+++ head/sys/dev/hyperv/vmbus/hv_channel.c	Tue Jul 19 05:46:15 2016	(r303020)
@@ -1250,61 +1250,63 @@ vmbus_chan_destroy_all(struct vmbus_soft
 	mtx_unlock(&sc->vmbus_prichan_lock);
 }
 
-/**
- * @brief Select the best outgoing channel
- * 
+/*
  * The channel whose vcpu binding is closest to the currect vcpu will
  * be selected.
- * If no multi-channel, always select primary channel
- * 
- * @param primary - primary channel
+ * If no multi-channel, always select primary channel.
  */
 struct hv_vmbus_channel *
-vmbus_select_outgoing_channel(struct hv_vmbus_channel *primary)
+vmbus_chan_cpu2chan(struct hv_vmbus_channel *prichan, int cpu)
 {
-	hv_vmbus_channel *new_channel = NULL;
-	hv_vmbus_channel *outgoing_channel = primary;
-	int old_cpu_distance = 0;
-	int new_cpu_distance = 0;
-	int cur_vcpu = 0;
-	int smp_pro_id = PCPU_GET(cpuid);
+	struct hv_vmbus_channel *sel, *chan;
+	uint32_t vcpu, sel_dist;
 
-	if (TAILQ_EMPTY(&primary->ch_subchans)) {
-		return outgoing_channel;
-	}
+	KASSERT(cpu >= 0 && cpu < mp_ncpus, ("invalid cpuid %d", cpu));
+	if (TAILQ_EMPTY(&prichan->ch_subchans))
+		return prichan;
 
-	if (smp_pro_id >= MAXCPU) {
-		return outgoing_channel;
-	}
+	vcpu = VMBUS_PCPU_GET(prichan->vmbus_sc, vcpuid, cpu);
 
-	cur_vcpu = VMBUS_PCPU_GET(primary->vmbus_sc, vcpuid, smp_pro_id);
-	
-	/* XXX need lock */
-	TAILQ_FOREACH(new_channel, &primary->ch_subchans, ch_sublink) {
-		if ((new_channel->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0) {
-			continue;
-		}
+#define CHAN_VCPU_DIST(ch, vcpu)		\
+	(((ch)->ch_vcpuid > (vcpu)) ?		\
+	 ((ch)->ch_vcpuid - (vcpu)) : ((vcpu) - (ch)->ch_vcpuid))
 
-		if (new_channel->ch_vcpuid == cur_vcpu){
-			return new_channel;
-		}
+#define CHAN_SELECT(ch)				\
+do {						\
+	sel = ch;				\
+	sel_dist = CHAN_VCPU_DIST(ch, vcpu);	\
+} while (0)
+
+	CHAN_SELECT(prichan);
 
-		old_cpu_distance = ((outgoing_channel->ch_vcpuid > cur_vcpu) ?
-		    (outgoing_channel->ch_vcpuid - cur_vcpu) :
-		    (cur_vcpu - outgoing_channel->ch_vcpuid));
-
-		new_cpu_distance = ((new_channel->ch_vcpuid > cur_vcpu) ?
-		    (new_channel->ch_vcpuid - cur_vcpu) :
-		    (cur_vcpu - new_channel->ch_vcpuid));
+	mtx_lock(&prichan->ch_subchan_lock);
+	TAILQ_FOREACH(chan, &prichan->ch_subchans, ch_sublink) {
+		uint32_t dist;
 
-		if (old_cpu_distance < new_cpu_distance) {
+		KASSERT(chan->ch_stflags & VMBUS_CHAN_ST_OPENED,
+		    ("chan%u is not opened", chan->ch_id));
+
+		if (chan->ch_vcpuid == vcpu) {
+			/* Exact match; done */
+			CHAN_SELECT(chan);
+			break;
+		}
+
+		dist = CHAN_VCPU_DIST(chan, vcpu);
+		if (sel_dist <= dist) {
+			/* Far or same distance; skip */
 			continue;
 		}
 
-		outgoing_channel = new_channel;
+		/* Select the closer channel. */
+		CHAN_SELECT(chan);
 	}
+	mtx_unlock(&prichan->ch_subchan_lock);
+
+#undef CHAN_SELECT
+#undef CHAN_VCPU_DIST
 
-	return(outgoing_channel);
+	return sel;
 }
 
 struct hv_vmbus_channel **


More information about the svn-src-head mailing list