diff options
| -rw-r--r-- | drivers/powercap/intel_rapl.c | 107 |
1 files changed, 82 insertions, 25 deletions
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 2e8f2be5b6f9..fbab29dfa793 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c | |||
| @@ -336,14 +336,14 @@ static int release_zone(struct powercap_zone *power_zone) | |||
| 336 | 336 | ||
| 337 | static int find_nr_power_limit(struct rapl_domain *rd) | 337 | static int find_nr_power_limit(struct rapl_domain *rd) |
| 338 | { | 338 | { |
| 339 | int i; | 339 | int i, nr_pl = 0; |
| 340 | 340 | ||
| 341 | for (i = 0; i < NR_POWER_LIMITS; i++) { | 341 | for (i = 0; i < NR_POWER_LIMITS; i++) { |
| 342 | if (rd->rpl[i].name == NULL) | 342 | if (rd->rpl[i].name) |
| 343 | break; | 343 | nr_pl++; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | return i; | 346 | return nr_pl; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | static int set_domain_enable(struct powercap_zone *power_zone, bool mode) | 349 | static int set_domain_enable(struct powercap_zone *power_zone, bool mode) |
| @@ -426,15 +426,38 @@ static const struct powercap_zone_ops zone_ops[] = { | |||
| 426 | }, | 426 | }, |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | static int set_power_limit(struct powercap_zone *power_zone, int id, | 429 | |
| 430 | /* | ||
| 431 | * Constraint index used by powercap can be different than power limit (PL) | ||
| 432 | * index in that some PLs maybe missing due to non-existant MSRs. So we | ||
| 433 | * need to convert here by finding the valid PLs only (name populated). | ||
| 434 | */ | ||
| 435 | static int contraint_to_pl(struct rapl_domain *rd, int cid) | ||
| 436 | { | ||
| 437 | int i, j; | ||
| 438 | |||
| 439 | for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) { | ||
| 440 | if ((rd->rpl[i].name) && j++ == cid) { | ||
| 441 | pr_debug("%s: index %d\n", __func__, i); | ||
| 442 | return i; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | return -EINVAL; | ||
| 447 | } | ||
| 448 | |||
| 449 | static int set_power_limit(struct powercap_zone *power_zone, int cid, | ||
| 430 | u64 power_limit) | 450 | u64 power_limit) |
| 431 | { | 451 | { |
| 432 | struct rapl_domain *rd; | 452 | struct rapl_domain *rd; |
| 433 | struct rapl_package *rp; | 453 | struct rapl_package *rp; |
| 434 | int ret = 0; | 454 | int ret = 0; |
| 455 | int id; | ||
| 435 | 456 | ||
| 436 | get_online_cpus(); | 457 | get_online_cpus(); |
| 437 | rd = power_zone_to_rapl_domain(power_zone); | 458 | rd = power_zone_to_rapl_domain(power_zone); |
| 459 | id = contraint_to_pl(rd, cid); | ||
| 460 | |||
| 438 | rp = rd->rp; | 461 | rp = rd->rp; |
| 439 | 462 | ||
| 440 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) { | 463 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) { |
| @@ -461,16 +484,18 @@ set_exit: | |||
| 461 | return ret; | 484 | return ret; |
| 462 | } | 485 | } |
| 463 | 486 | ||
| 464 | static int get_current_power_limit(struct powercap_zone *power_zone, int id, | 487 | static int get_current_power_limit(struct powercap_zone *power_zone, int cid, |
| 465 | u64 *data) | 488 | u64 *data) |
| 466 | { | 489 | { |
| 467 | struct rapl_domain *rd; | 490 | struct rapl_domain *rd; |
| 468 | u64 val; | 491 | u64 val; |
| 469 | int prim; | 492 | int prim; |
| 470 | int ret = 0; | 493 | int ret = 0; |
| 494 | int id; | ||
| 471 | 495 | ||
| 472 | get_online_cpus(); | 496 | get_online_cpus(); |
| 473 | rd = power_zone_to_rapl_domain(power_zone); | 497 | rd = power_zone_to_rapl_domain(power_zone); |
| 498 | id = contraint_to_pl(rd, cid); | ||
| 474 | switch (rd->rpl[id].prim_id) { | 499 | switch (rd->rpl[id].prim_id) { |
| 475 | case PL1_ENABLE: | 500 | case PL1_ENABLE: |
| 476 | prim = POWER_LIMIT1; | 501 | prim = POWER_LIMIT1; |
| @@ -492,14 +517,17 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int id, | |||
| 492 | return ret; | 517 | return ret; |
| 493 | } | 518 | } |
| 494 | 519 | ||
| 495 | static int set_time_window(struct powercap_zone *power_zone, int id, | 520 | static int set_time_window(struct powercap_zone *power_zone, int cid, |
| 496 | u64 window) | 521 | u64 window) |
| 497 | { | 522 | { |
| 498 | struct rapl_domain *rd; | 523 | struct rapl_domain *rd; |
| 499 | int ret = 0; | 524 | int ret = 0; |
| 525 | int id; | ||
| 500 | 526 | ||
| 501 | get_online_cpus(); | 527 | get_online_cpus(); |
| 502 | rd = power_zone_to_rapl_domain(power_zone); | 528 | rd = power_zone_to_rapl_domain(power_zone); |
| 529 | id = contraint_to_pl(rd, cid); | ||
| 530 | |||
| 503 | switch (rd->rpl[id].prim_id) { | 531 | switch (rd->rpl[id].prim_id) { |
| 504 | case PL1_ENABLE: | 532 | case PL1_ENABLE: |
| 505 | rapl_write_data_raw(rd, TIME_WINDOW1, window); | 533 | rapl_write_data_raw(rd, TIME_WINDOW1, window); |
| @@ -514,14 +542,17 @@ static int set_time_window(struct powercap_zone *power_zone, int id, | |||
| 514 | return ret; | 542 | return ret; |
| 515 | } | 543 | } |
| 516 | 544 | ||
| 517 | static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data) | 545 | static int get_time_window(struct powercap_zone *power_zone, int cid, u64 *data) |
| 518 | { | 546 | { |
| 519 | struct rapl_domain *rd; | 547 | struct rapl_domain *rd; |
| 520 | u64 val; | 548 | u64 val; |
| 521 | int ret = 0; | 549 | int ret = 0; |
| 550 | int id; | ||
| 522 | 551 | ||
| 523 | get_online_cpus(); | 552 | get_online_cpus(); |
| 524 | rd = power_zone_to_rapl_domain(power_zone); | 553 | rd = power_zone_to_rapl_domain(power_zone); |
| 554 | id = contraint_to_pl(rd, cid); | ||
| 555 | |||
| 525 | switch (rd->rpl[id].prim_id) { | 556 | switch (rd->rpl[id].prim_id) { |
| 526 | case PL1_ENABLE: | 557 | case PL1_ENABLE: |
| 527 | ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val); | 558 | ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val); |
| @@ -540,15 +571,17 @@ static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data) | |||
| 540 | return ret; | 571 | return ret; |
| 541 | } | 572 | } |
| 542 | 573 | ||
| 543 | static const char *get_constraint_name(struct powercap_zone *power_zone, int id) | 574 | static const char *get_constraint_name(struct powercap_zone *power_zone, int cid) |
| 544 | { | 575 | { |
| 545 | struct rapl_power_limit *rpl; | ||
| 546 | struct rapl_domain *rd; | 576 | struct rapl_domain *rd; |
| 577 | int id; | ||
| 547 | 578 | ||
| 548 | rd = power_zone_to_rapl_domain(power_zone); | 579 | rd = power_zone_to_rapl_domain(power_zone); |
| 549 | rpl = (struct rapl_power_limit *) &rd->rpl[id]; | 580 | id = contraint_to_pl(rd, cid); |
| 581 | if (id >= 0) | ||
| 582 | return rd->rpl[id].name; | ||
| 550 | 583 | ||
| 551 | return rpl->name; | 584 | return NULL; |
| 552 | } | 585 | } |
| 553 | 586 | ||
| 554 | 587 | ||
| @@ -1101,6 +1134,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { | |||
| 1101 | RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core), | 1134 | RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core), |
| 1102 | 1135 | ||
| 1103 | RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core), | 1136 | RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core), |
| 1137 | RAPL_CPU(INTEL_FAM6_IVYBRIDGE_X, rapl_defaults_core), | ||
| 1104 | 1138 | ||
| 1105 | RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core), | 1139 | RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core), |
| 1106 | RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core), | 1140 | RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core), |
| @@ -1123,6 +1157,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { | |||
| 1123 | RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD1, rapl_defaults_tng), | 1157 | RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD1, rapl_defaults_tng), |
| 1124 | RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD2, rapl_defaults_ann), | 1158 | RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD2, rapl_defaults_ann), |
| 1125 | RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), | 1159 | RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), |
| 1160 | RAPL_CPU(INTEL_FAM6_ATOM_DENVERTON, rapl_defaults_core), | ||
| 1126 | 1161 | ||
| 1127 | RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), | 1162 | RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), |
| 1128 | {} | 1163 | {} |
| @@ -1381,6 +1416,37 @@ static int rapl_check_domain(int cpu, int domain) | |||
| 1381 | return 0; | 1416 | return 0; |
| 1382 | } | 1417 | } |
| 1383 | 1418 | ||
| 1419 | |||
| 1420 | /* | ||
| 1421 | * Check if power limits are available. Two cases when they are not available: | ||
| 1422 | * 1. Locked by BIOS, in this case we still provide read-only access so that | ||
| 1423 | * users can see what limit is set by the BIOS. | ||
| 1424 | * 2. Some CPUs make some domains monitoring only which means PLx MSRs may not | ||
| 1425 | * exist at all. In this case, we do not show the contraints in powercap. | ||
| 1426 | * | ||
| 1427 | * Called after domains are detected and initialized. | ||
| 1428 | */ | ||
| 1429 | static void rapl_detect_powerlimit(struct rapl_domain *rd) | ||
| 1430 | { | ||
| 1431 | u64 val64; | ||
| 1432 | int i; | ||
| 1433 | |||
| 1434 | /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */ | ||
| 1435 | if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) { | ||
| 1436 | if (val64) { | ||
| 1437 | pr_info("RAPL package %d domain %s locked by BIOS\n", | ||
| 1438 | rd->rp->id, rd->name); | ||
| 1439 | rd->state |= DOMAIN_STATE_BIOS_LOCKED; | ||
| 1440 | } | ||
| 1441 | } | ||
| 1442 | /* check if power limit MSRs exists, otherwise domain is monitoring only */ | ||
| 1443 | for (i = 0; i < NR_POWER_LIMITS; i++) { | ||
| 1444 | int prim = rd->rpl[i].prim_id; | ||
| 1445 | if (rapl_read_data_raw(rd, prim, false, &val64)) | ||
| 1446 | rd->rpl[i].name = NULL; | ||
| 1447 | } | ||
| 1448 | } | ||
| 1449 | |||
| 1384 | /* Detect active and valid domains for the given CPU, caller must | 1450 | /* Detect active and valid domains for the given CPU, caller must |
| 1385 | * ensure the CPU belongs to the targeted package and CPU hotlug is disabled. | 1451 | * ensure the CPU belongs to the targeted package and CPU hotlug is disabled. |
| 1386 | */ | 1452 | */ |
| @@ -1389,7 +1455,6 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) | |||
| 1389 | int i; | 1455 | int i; |
| 1390 | int ret = 0; | 1456 | int ret = 0; |
| 1391 | struct rapl_domain *rd; | 1457 | struct rapl_domain *rd; |
| 1392 | u64 locked; | ||
| 1393 | 1458 | ||
| 1394 | for (i = 0; i < RAPL_DOMAIN_MAX; i++) { | 1459 | for (i = 0; i < RAPL_DOMAIN_MAX; i++) { |
| 1395 | /* use physical package id to read counters */ | 1460 | /* use physical package id to read counters */ |
| @@ -1400,7 +1465,7 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) | |||
| 1400 | } | 1465 | } |
| 1401 | rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); | 1466 | rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); |
| 1402 | if (!rp->nr_domains) { | 1467 | if (!rp->nr_domains) { |
| 1403 | pr_err("no valid rapl domains found in package %d\n", rp->id); | 1468 | pr_debug("no valid rapl domains found in package %d\n", rp->id); |
| 1404 | ret = -ENODEV; | 1469 | ret = -ENODEV; |
| 1405 | goto done; | 1470 | goto done; |
| 1406 | } | 1471 | } |
| @@ -1414,17 +1479,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) | |||
| 1414 | } | 1479 | } |
| 1415 | rapl_init_domains(rp); | 1480 | rapl_init_domains(rp); |
| 1416 | 1481 | ||
| 1417 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { | 1482 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) |
| 1418 | /* check if the domain is locked by BIOS */ | 1483 | rapl_detect_powerlimit(rd); |
| 1419 | ret = rapl_read_data_raw(rd, FW_LOCK, false, &locked); | 1484 | |
| 1420 | if (ret) | ||
| 1421 | return ret; | ||
| 1422 | if (locked) { | ||
| 1423 | pr_info("RAPL package %d domain %s locked by BIOS\n", | ||
| 1424 | rp->id, rd->name); | ||
| 1425 | rd->state |= DOMAIN_STATE_BIOS_LOCKED; | ||
| 1426 | } | ||
| 1427 | } | ||
| 1428 | 1485 | ||
| 1429 | 1486 | ||
| 1430 | done: | 1487 | done: |
