0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #define pr_fmt(fmt) "ACPI PPTT: " fmt
0019
0020 #include <linux/acpi.h>
0021 #include <linux/cacheinfo.h>
0022 #include <acpi/processor.h>
0023
0024 static struct acpi_subtable_header *fetch_pptt_subtable(struct acpi_table_header *table_hdr,
0025 u32 pptt_ref)
0026 {
0027 struct acpi_subtable_header *entry;
0028
0029
0030 if (pptt_ref < sizeof(struct acpi_subtable_header))
0031 return NULL;
0032
0033 if (pptt_ref + sizeof(struct acpi_subtable_header) > table_hdr->length)
0034 return NULL;
0035
0036 entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, pptt_ref);
0037
0038 if (entry->length == 0)
0039 return NULL;
0040
0041 if (pptt_ref + entry->length > table_hdr->length)
0042 return NULL;
0043
0044 return entry;
0045 }
0046
0047 static struct acpi_pptt_processor *fetch_pptt_node(struct acpi_table_header *table_hdr,
0048 u32 pptt_ref)
0049 {
0050 return (struct acpi_pptt_processor *)fetch_pptt_subtable(table_hdr, pptt_ref);
0051 }
0052
0053 static struct acpi_pptt_cache *fetch_pptt_cache(struct acpi_table_header *table_hdr,
0054 u32 pptt_ref)
0055 {
0056 return (struct acpi_pptt_cache *)fetch_pptt_subtable(table_hdr, pptt_ref);
0057 }
0058
0059 static struct acpi_subtable_header *acpi_get_pptt_resource(struct acpi_table_header *table_hdr,
0060 struct acpi_pptt_processor *node,
0061 int resource)
0062 {
0063 u32 *ref;
0064
0065 if (resource >= node->number_of_priv_resources)
0066 return NULL;
0067
0068 ref = ACPI_ADD_PTR(u32, node, sizeof(struct acpi_pptt_processor));
0069 ref += resource;
0070
0071 return fetch_pptt_subtable(table_hdr, *ref);
0072 }
0073
0074 static inline bool acpi_pptt_match_type(int table_type, int type)
0075 {
0076 return ((table_type & ACPI_PPTT_MASK_CACHE_TYPE) == type ||
0077 table_type & ACPI_PPTT_CACHE_TYPE_UNIFIED & type);
0078 }
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 static unsigned int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr,
0102 unsigned int local_level,
0103 struct acpi_subtable_header *res,
0104 struct acpi_pptt_cache **found,
0105 unsigned int level, int type)
0106 {
0107 struct acpi_pptt_cache *cache;
0108
0109 if (res->type != ACPI_PPTT_TYPE_CACHE)
0110 return 0;
0111
0112 cache = (struct acpi_pptt_cache *) res;
0113 while (cache) {
0114 local_level++;
0115
0116 if (local_level == level &&
0117 cache->flags & ACPI_PPTT_CACHE_TYPE_VALID &&
0118 acpi_pptt_match_type(cache->attributes, type)) {
0119 if (*found != NULL && cache != *found)
0120 pr_warn("Found duplicate cache level/type unable to determine uniqueness\n");
0121
0122 pr_debug("Found cache @ level %u\n", level);
0123 *found = cache;
0124
0125
0126
0127
0128
0129 }
0130 cache = fetch_pptt_cache(table_hdr, cache->next_level_of_cache);
0131 }
0132 return local_level;
0133 }
0134
0135 static struct acpi_pptt_cache *
0136 acpi_find_cache_level(struct acpi_table_header *table_hdr,
0137 struct acpi_pptt_processor *cpu_node,
0138 unsigned int *starting_level, unsigned int level,
0139 int type)
0140 {
0141 struct acpi_subtable_header *res;
0142 unsigned int number_of_levels = *starting_level;
0143 int resource = 0;
0144 struct acpi_pptt_cache *ret = NULL;
0145 unsigned int local_level;
0146
0147
0148 while ((res = acpi_get_pptt_resource(table_hdr, cpu_node, resource))) {
0149 resource++;
0150
0151 local_level = acpi_pptt_walk_cache(table_hdr, *starting_level,
0152 res, &ret, level, type);
0153
0154
0155
0156
0157
0158 if (number_of_levels < local_level)
0159 number_of_levels = local_level;
0160 }
0161 if (number_of_levels > *starting_level)
0162 *starting_level = number_of_levels;
0163
0164 return ret;
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 static int acpi_count_levels(struct acpi_table_header *table_hdr,
0181 struct acpi_pptt_processor *cpu_node)
0182 {
0183 int total_levels = 0;
0184
0185 do {
0186 acpi_find_cache_level(table_hdr, cpu_node, &total_levels, 0, 0);
0187 cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
0188 } while (cpu_node);
0189
0190 return total_levels;
0191 }
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 static int acpi_pptt_leaf_node(struct acpi_table_header *table_hdr,
0205 struct acpi_pptt_processor *node)
0206 {
0207 struct acpi_subtable_header *entry;
0208 unsigned long table_end;
0209 u32 node_entry;
0210 struct acpi_pptt_processor *cpu_node;
0211 u32 proc_sz;
0212
0213 if (table_hdr->revision > 1)
0214 return (node->flags & ACPI_PPTT_ACPI_LEAF_NODE);
0215
0216 table_end = (unsigned long)table_hdr + table_hdr->length;
0217 node_entry = ACPI_PTR_DIFF(node, table_hdr);
0218 entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr,
0219 sizeof(struct acpi_table_pptt));
0220 proc_sz = sizeof(struct acpi_pptt_processor *);
0221
0222 while ((unsigned long)entry + proc_sz < table_end) {
0223 cpu_node = (struct acpi_pptt_processor *)entry;
0224 if (entry->type == ACPI_PPTT_TYPE_PROCESSOR &&
0225 cpu_node->parent == node_entry)
0226 return 0;
0227 if (entry->length == 0)
0228 return 0;
0229 entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
0230 entry->length);
0231
0232 }
0233 return 1;
0234 }
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_header *table_hdr,
0251 u32 acpi_cpu_id)
0252 {
0253 struct acpi_subtable_header *entry;
0254 unsigned long table_end;
0255 struct acpi_pptt_processor *cpu_node;
0256 u32 proc_sz;
0257
0258 table_end = (unsigned long)table_hdr + table_hdr->length;
0259 entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr,
0260 sizeof(struct acpi_table_pptt));
0261 proc_sz = sizeof(struct acpi_pptt_processor *);
0262
0263
0264 while ((unsigned long)entry + proc_sz < table_end) {
0265 cpu_node = (struct acpi_pptt_processor *)entry;
0266
0267 if (entry->length == 0) {
0268 pr_warn("Invalid zero length subtable\n");
0269 break;
0270 }
0271 if (entry->type == ACPI_PPTT_TYPE_PROCESSOR &&
0272 acpi_cpu_id == cpu_node->acpi_processor_id &&
0273 acpi_pptt_leaf_node(table_hdr, cpu_node)) {
0274 return (struct acpi_pptt_processor *)entry;
0275 }
0276
0277 entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry,
0278 entry->length);
0279 }
0280
0281 return NULL;
0282 }
0283
0284 static int acpi_find_cache_levels(struct acpi_table_header *table_hdr,
0285 u32 acpi_cpu_id)
0286 {
0287 int number_of_levels = 0;
0288 struct acpi_pptt_processor *cpu;
0289
0290 cpu = acpi_find_processor_node(table_hdr, acpi_cpu_id);
0291 if (cpu)
0292 number_of_levels = acpi_count_levels(table_hdr, cpu);
0293
0294 return number_of_levels;
0295 }
0296
0297 static u8 acpi_cache_type(enum cache_type type)
0298 {
0299 switch (type) {
0300 case CACHE_TYPE_DATA:
0301 pr_debug("Looking for data cache\n");
0302 return ACPI_PPTT_CACHE_TYPE_DATA;
0303 case CACHE_TYPE_INST:
0304 pr_debug("Looking for instruction cache\n");
0305 return ACPI_PPTT_CACHE_TYPE_INSTR;
0306 default:
0307 case CACHE_TYPE_UNIFIED:
0308 pr_debug("Looking for unified cache\n");
0309
0310
0311
0312
0313
0314
0315 return ACPI_PPTT_CACHE_TYPE_UNIFIED;
0316 }
0317 }
0318
0319 static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *table_hdr,
0320 u32 acpi_cpu_id,
0321 enum cache_type type,
0322 unsigned int level,
0323 struct acpi_pptt_processor **node)
0324 {
0325 unsigned int total_levels = 0;
0326 struct acpi_pptt_cache *found = NULL;
0327 struct acpi_pptt_processor *cpu_node;
0328 u8 acpi_type = acpi_cache_type(type);
0329
0330 pr_debug("Looking for CPU %d's level %u cache type %d\n",
0331 acpi_cpu_id, level, acpi_type);
0332
0333 cpu_node = acpi_find_processor_node(table_hdr, acpi_cpu_id);
0334
0335 while (cpu_node && !found) {
0336 found = acpi_find_cache_level(table_hdr, cpu_node,
0337 &total_levels, level, acpi_type);
0338 *node = cpu_node;
0339 cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
0340 }
0341
0342 return found;
0343 }
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 static void update_cache_properties(struct cacheinfo *this_leaf,
0359 struct acpi_pptt_cache *found_cache,
0360 struct acpi_pptt_processor *cpu_node,
0361 u8 revision)
0362 {
0363 struct acpi_pptt_cache_v1* found_cache_v1;
0364
0365 this_leaf->fw_token = cpu_node;
0366 if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID)
0367 this_leaf->size = found_cache->size;
0368 if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID)
0369 this_leaf->coherency_line_size = found_cache->line_size;
0370 if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID)
0371 this_leaf->number_of_sets = found_cache->number_of_sets;
0372 if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID)
0373 this_leaf->ways_of_associativity = found_cache->associativity;
0374 if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID) {
0375 switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) {
0376 case ACPI_PPTT_CACHE_POLICY_WT:
0377 this_leaf->attributes = CACHE_WRITE_THROUGH;
0378 break;
0379 case ACPI_PPTT_CACHE_POLICY_WB:
0380 this_leaf->attributes = CACHE_WRITE_BACK;
0381 break;
0382 }
0383 }
0384 if (found_cache->flags & ACPI_PPTT_ALLOCATION_TYPE_VALID) {
0385 switch (found_cache->attributes & ACPI_PPTT_MASK_ALLOCATION_TYPE) {
0386 case ACPI_PPTT_CACHE_READ_ALLOCATE:
0387 this_leaf->attributes |= CACHE_READ_ALLOCATE;
0388 break;
0389 case ACPI_PPTT_CACHE_WRITE_ALLOCATE:
0390 this_leaf->attributes |= CACHE_WRITE_ALLOCATE;
0391 break;
0392 case ACPI_PPTT_CACHE_RW_ALLOCATE:
0393 case ACPI_PPTT_CACHE_RW_ALLOCATE_ALT:
0394 this_leaf->attributes |=
0395 CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE;
0396 break;
0397 }
0398 }
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 if (this_leaf->type == CACHE_TYPE_NOCACHE &&
0410 found_cache->flags & ACPI_PPTT_CACHE_TYPE_VALID)
0411 this_leaf->type = CACHE_TYPE_UNIFIED;
0412
0413 if (revision >= 3 && (found_cache->flags & ACPI_PPTT_CACHE_ID_VALID)) {
0414 found_cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1,
0415 found_cache, sizeof(struct acpi_pptt_cache));
0416 this_leaf->id = found_cache_v1->cache_id;
0417 this_leaf->attributes |= CACHE_ID;
0418 }
0419 }
0420
0421 static void cache_setup_acpi_cpu(struct acpi_table_header *table,
0422 unsigned int cpu)
0423 {
0424 struct acpi_pptt_cache *found_cache;
0425 struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
0426 u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
0427 struct cacheinfo *this_leaf;
0428 unsigned int index = 0;
0429 struct acpi_pptt_processor *cpu_node = NULL;
0430
0431 while (index < get_cpu_cacheinfo(cpu)->num_leaves) {
0432 this_leaf = this_cpu_ci->info_list + index;
0433 found_cache = acpi_find_cache_node(table, acpi_cpu_id,
0434 this_leaf->type,
0435 this_leaf->level,
0436 &cpu_node);
0437 pr_debug("found = %p %p\n", found_cache, cpu_node);
0438 if (found_cache)
0439 update_cache_properties(this_leaf, found_cache,
0440 ACPI_TO_POINTER(ACPI_PTR_DIFF(cpu_node, table)),
0441 table->revision);
0442
0443 index++;
0444 }
0445 }
0446
0447 static bool flag_identical(struct acpi_table_header *table_hdr,
0448 struct acpi_pptt_processor *cpu)
0449 {
0450 struct acpi_pptt_processor *next;
0451
0452
0453 if (table_hdr->revision < 2)
0454 return false;
0455
0456
0457 if (cpu->flags & ACPI_PPTT_ACPI_IDENTICAL) {
0458 next = fetch_pptt_node(table_hdr, cpu->parent);
0459 if (!(next && next->flags & ACPI_PPTT_ACPI_IDENTICAL))
0460 return true;
0461 }
0462
0463 return false;
0464 }
0465
0466
0467 #define PPTT_ABORT_PACKAGE 0xFF
0468
0469 static struct acpi_pptt_processor *acpi_find_processor_tag(struct acpi_table_header *table_hdr,
0470 struct acpi_pptt_processor *cpu,
0471 int level, int flag)
0472 {
0473 struct acpi_pptt_processor *prev_node;
0474
0475 while (cpu && level) {
0476
0477 if (flag == ACPI_PPTT_ACPI_IDENTICAL) {
0478 if (flag_identical(table_hdr, cpu))
0479 break;
0480 } else if (cpu->flags & flag)
0481 break;
0482 pr_debug("level %d\n", level);
0483 prev_node = fetch_pptt_node(table_hdr, cpu->parent);
0484 if (prev_node == NULL)
0485 break;
0486 cpu = prev_node;
0487 level--;
0488 }
0489 return cpu;
0490 }
0491
0492 static void acpi_pptt_warn_missing(void)
0493 {
0494 pr_warn_once("No PPTT table found, CPU and cache topology may be inaccurate\n");
0495 }
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510 static int topology_get_acpi_cpu_tag(struct acpi_table_header *table,
0511 unsigned int cpu, int level, int flag)
0512 {
0513 struct acpi_pptt_processor *cpu_node;
0514 u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
0515
0516 cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
0517 if (cpu_node) {
0518 cpu_node = acpi_find_processor_tag(table, cpu_node,
0519 level, flag);
0520
0521
0522
0523
0524
0525
0526 if (level == 0 ||
0527 cpu_node->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID)
0528 return cpu_node->acpi_processor_id;
0529 return ACPI_PTR_DIFF(cpu_node, table);
0530 }
0531 pr_warn_once("PPTT table found, but unable to locate core %d (%d)\n",
0532 cpu, acpi_cpu_id);
0533 return -ENOENT;
0534 }
0535
0536
0537 static struct acpi_table_header *acpi_get_pptt(void)
0538 {
0539 static struct acpi_table_header *pptt;
0540 acpi_status status;
0541
0542
0543
0544
0545
0546 if (!pptt) {
0547 status = acpi_get_table(ACPI_SIG_PPTT, 0, &pptt);
0548 if (ACPI_FAILURE(status))
0549 acpi_pptt_warn_missing();
0550 }
0551
0552 return pptt;
0553 }
0554
0555 static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag)
0556 {
0557 struct acpi_table_header *table;
0558 int retval;
0559
0560 table = acpi_get_pptt();
0561 if (!table)
0562 return -ENOENT;
0563
0564 retval = topology_get_acpi_cpu_tag(table, cpu, level, flag);
0565 pr_debug("Topology Setup ACPI CPU %d, level %d ret = %d\n",
0566 cpu, level, retval);
0567
0568 return retval;
0569 }
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584 static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag)
0585 {
0586 struct acpi_table_header *table;
0587 u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
0588 struct acpi_pptt_processor *cpu_node = NULL;
0589 int ret = -ENOENT;
0590
0591 table = acpi_get_pptt();
0592 if (!table)
0593 return -ENOENT;
0594
0595 if (table->revision >= rev)
0596 cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
0597
0598 if (cpu_node)
0599 ret = (cpu_node->flags & flag) != 0;
0600
0601 return ret;
0602 }
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614 int acpi_find_last_cache_level(unsigned int cpu)
0615 {
0616 u32 acpi_cpu_id;
0617 struct acpi_table_header *table;
0618 int number_of_levels = 0;
0619
0620 table = acpi_get_pptt();
0621 if (!table)
0622 return -ENOENT;
0623
0624 pr_debug("Cache Setup find last level CPU=%d\n", cpu);
0625
0626 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
0627 number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id);
0628 pr_debug("Cache Setup find last level level=%d\n", number_of_levels);
0629
0630 return number_of_levels;
0631 }
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646 int cache_setup_acpi(unsigned int cpu)
0647 {
0648 struct acpi_table_header *table;
0649
0650 table = acpi_get_pptt();
0651 if (!table)
0652 return -ENOENT;
0653
0654 pr_debug("Cache Setup ACPI CPU %d\n", cpu);
0655
0656 cache_setup_acpi_cpu(table, cpu);
0657
0658 return 0;
0659 }
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670 int acpi_pptt_cpu_is_thread(unsigned int cpu)
0671 {
0672 return check_acpi_cpu_flag(cpu, 2, ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD);
0673 }
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693 int find_acpi_cpu_topology(unsigned int cpu, int level)
0694 {
0695 return find_acpi_cpu_topology_tag(cpu, level, 0);
0696 }
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711 int find_acpi_cpu_topology_package(unsigned int cpu)
0712 {
0713 return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE,
0714 ACPI_PPTT_PHYSICAL_PACKAGE);
0715 }
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734 int find_acpi_cpu_topology_cluster(unsigned int cpu)
0735 {
0736 struct acpi_table_header *table;
0737 struct acpi_pptt_processor *cpu_node, *cluster_node;
0738 u32 acpi_cpu_id;
0739 int retval;
0740 int is_thread;
0741
0742 table = acpi_get_pptt();
0743 if (!table)
0744 return -ENOENT;
0745
0746 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
0747 cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
0748 if (!cpu_node || !cpu_node->parent)
0749 return -ENOENT;
0750
0751 is_thread = cpu_node->flags & ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD;
0752 cluster_node = fetch_pptt_node(table, cpu_node->parent);
0753 if (!cluster_node)
0754 return -ENOENT;
0755
0756 if (is_thread) {
0757 if (!cluster_node->parent)
0758 return -ENOENT;
0759
0760 cluster_node = fetch_pptt_node(table, cluster_node->parent);
0761 if (!cluster_node)
0762 return -ENOENT;
0763 }
0764 if (cluster_node->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID)
0765 retval = cluster_node->acpi_processor_id;
0766 else
0767 retval = ACPI_PTR_DIFF(cluster_node, table);
0768
0769 return retval;
0770 }
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792 int find_acpi_cpu_topology_hetero_id(unsigned int cpu)
0793 {
0794 return find_acpi_cpu_topology_tag(cpu, PPTT_ABORT_PACKAGE,
0795 ACPI_PPTT_ACPI_IDENTICAL);
0796 }