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 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 | ||
| 260 | enum { | ||
| 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 | */ | ||
| 272 | static 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 | */ | ||
| 304 | static 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 | */ | ||
| 315 | static 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)); |
