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-all
mailing list