aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv/channel_mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hv/channel_mgmt.c')
-rw-r--r--drivers/hv/channel_mgmt.c85
1 files changed, 84 insertions, 1 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 56ed45c74d01..c80fe6245f5b 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)
257 } 257 }
258} 258}
259 259
260enum {
261 IDE = 0,
262 SCSI,
263 NIC,
264 MAX_PERF_CHN,
265};
266
267/*
268 * This is an array of channels (devices) that are performance critical.
269 * We attempt to distribute the interrupt load for these devices across
270 * all available CPUs.
271 */
272static const uuid_le hp_devs[] = {
273 /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
274 /* IDE */
275 {
276 .b = {
277 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
278 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
279 }
280 },
281 /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
282 /* Storage - SCSI */
283 {
284 .b = {
285 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
286 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
287 }
288 },
289 /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
290 /* Network */
291 {
292 .b = {
293 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
294 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
295 }
296 },
297
298};
299
300
301/*
302 * We use this state to statically distribute the channel interrupt load.
303 */
304static u32 next_vp;
305
306/*
307 * Starting with Win8, we can statically distribute the incoming
308 * channel interrupt load by binding a channel to VCPU. We
309 * implement here a simple round robin scheme for distributing
310 * the interrupt load.
311 * We will bind channels that are not performance critical to cpu 0 and
312 * performance critical channels (IDE, SCSI and Network) will be uniformly
313 * distributed across all available CPUs.
314 */
315static u32 get_vp_index(uuid_le *type_guid)
316{
317 u32 cur_cpu;
318 int i;
319 bool perf_chn = false;
320 u32 max_cpus = num_online_cpus();
321
322 for (i = IDE; i < MAX_PERF_CHN; i++) {
323 if (!memcmp(type_guid->b, hp_devs[i].b,
324 sizeof(uuid_le))) {
325 perf_chn = true;
326 break;
327 }
328 }
329 if ((vmbus_proto_version == VERSION_WS2008) ||
330 (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
331 /*
332 * Prior to win8, all channel interrupts are
333 * delivered on cpu 0.
334 * Also if the channel is not a performance critical
335 * channel, bind it to cpu 0.
336 */
337 return 0;
338 }
339 cur_cpu = (++next_vp % max_cpus);
340 return hv_context.vp_index[cur_cpu];
341}
342
260/* 343/*
261 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition. 344 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
262 * 345 *
@@ -302,7 +385,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
302 offer->connection_id; 385 offer->connection_id;
303 } 386 }
304 387
305 newchannel->target_vp = 0; 388 newchannel->target_vp = get_vp_index(&offer->offer.if_type);
306 389
307 memcpy(&newchannel->offermsg, offer, 390 memcpy(&newchannel->offermsg, offer,
308 sizeof(struct vmbus_channel_offer_channel)); 391 sizeof(struct vmbus_channel_offer_channel));