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.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 2f84c5cff8d4..53a8600162a5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -257,6 +257,70 @@ 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 device_ids (device types) that are performance critical.
269 * We attempt to distribute the interrupt load for these devices across
270 * all available CPUs.
271 */
272static const struct hv_vmbus_device_id hp_devs[] = {
273 /* IDE */
274 { HV_IDE_GUID, },
275 /* Storage - SCSI */
276 { HV_SCSI_GUID, },
277 /* Network */
278 { HV_NIC_GUID, },
279};
280
281
282/*
283 * We use this state to statically distribute the channel interrupt load.
284 */
285static u32 next_vp;
286
287/*
288 * Starting with Win8, we can statically distribute the incoming
289 * channel interrupt load by binding a channel to VCPU. We
290 * implement here a simple round robin scheme for distributing
291 * the interrupt load.
292 * We will bind channels that are not performance critical to cpu 0 and
293 * performance critical channels (IDE, SCSI and Network) will be uniformly
294 * distributed across all available CPUs.
295 */
296static u32 get_vp_index(uuid_le *type_guid)
297{
298 u32 cur_cpu;
299 int i;
300 bool perf_chn = false;
301 u32 max_cpus = num_online_cpus();
302
303 for (i = IDE; i < MAX_PERF_CHN; i++) {
304 if (!memcmp(type_guid->b, hp_devs[i].guid,
305 sizeof(uuid_le))) {
306 perf_chn = true;
307 break;
308 }
309 }
310 if ((vmbus_proto_version == VERSION_WS2008) ||
311 (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
312 /*
313 * Prior to win8, all channel interrupts are
314 * delivered on cpu 0.
315 * Also if the channel is not a performance critical
316 * channel, bind it to cpu 0.
317 */
318 return 0;
319 }
320 cur_cpu = (++next_vp % max_cpus);
321 return 0;
322}
323
260/* 324/*
261 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition. 325 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
262 * 326 *
@@ -275,6 +339,35 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
275 return; 339 return;
276 } 340 }
277 341
342 /*
343 * By default we setup state to enable batched
344 * reading. A specific service can choose to
345 * disable this prior to opening the channel.
346 */
347 newchannel->batched_reading = true;
348
349 /*
350 * Setup state for signalling the host.
351 */
352 newchannel->sig_event = (struct hv_input_signal_event *)
353 (ALIGN((unsigned long)
354 &newchannel->sig_buf,
355 HV_HYPERCALL_PARAM_ALIGN));
356
357 newchannel->sig_event->connectionid.asu32 = 0;
358 newchannel->sig_event->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID;
359 newchannel->sig_event->flag_number = 0;
360 newchannel->sig_event->rsvdz = 0;
361
362 if (vmbus_proto_version != VERSION_WS2008) {
363 newchannel->is_dedicated_interrupt =
364 (offer->is_dedicated_interrupt != 0);
365 newchannel->sig_event->connectionid.u.id =
366 offer->connection_id;
367 }
368
369 newchannel->target_vp = get_vp_index(&offer->offer.if_type);
370
278 memcpy(&newchannel->offermsg, offer, 371 memcpy(&newchannel->offermsg, offer,
279 sizeof(struct vmbus_channel_offer_channel)); 372 sizeof(struct vmbus_channel_offer_channel));
280 newchannel->monitor_grp = (u8)offer->monitorid / 32; 373 newchannel->monitor_grp = (u8)offer->monitorid / 32;