diff options
-rw-r--r-- | drivers/hv/channel_mgmt.c | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 56ed45c74d0..c80fe6245f5 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -257,6 +257,89 @@ static void vmbus_process_offer(struct work_struct *work) } } +enum { + IDE = 0, + SCSI, + NIC, + MAX_PERF_CHN, +}; + +/* + * This is an array of channels (devices) that are performance critical. + * We attempt to distribute the interrupt load for these devices across + * all available CPUs. + */ +static const uuid_le hp_devs[] = { + /* {32412632-86cb-44a2-9b5c-50d1417354f5} */ + /* IDE */ + { + .b = { + 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, + 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 + } + }, + /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ + /* Storage - SCSI */ + { + .b = { + 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, + 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f + } + }, + /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ + /* Network */ + { + .b = { + 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, + 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E + } + }, + +}; + + +/* + * We use this state to statically distribute the channel interrupt load. + */ +static u32 next_vp; + +/* + * Starting with Win8, we can statically distribute the incoming + * channel interrupt load by binding a channel to VCPU. We + * implement here a simple round robin scheme for distributing + * the interrupt load. + * We will bind channels that are not performance critical to cpu 0 and + * performance critical channels (IDE, SCSI and Network) will be uniformly + * distributed across all available CPUs. + */ +static u32 get_vp_index(uuid_le *type_guid) +{ + u32 cur_cpu; + int i; + bool perf_chn = false; + u32 max_cpus = num_online_cpus(); + + for (i = IDE; i < MAX_PERF_CHN; i++) { + if (!memcmp(type_guid->b, hp_devs[i].b, + sizeof(uuid_le))) { + perf_chn = true; + break; + } + } + if ((vmbus_proto_version == VERSION_WS2008) || + (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) { + /* + * Prior to win8, all channel interrupts are + * delivered on cpu 0. + * Also if the channel is not a performance critical + * channel, bind it to cpu 0. + */ + return 0; + } + cur_cpu = (++next_vp % max_cpus); + return hv_context.vp_index[cur_cpu]; +} + /* * vmbus_onoffer - Handler for channel offers from vmbus in parent partition. * @@ -302,7 +385,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) offer->connection_id; } - newchannel->target_vp = 0; + newchannel->target_vp = get_vp_index(&offer->offer.if_type); memcpy(&newchannel->offermsg, offer, sizeof(struct vmbus_channel_offer_channel)); |