Motr  M0
processor.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-2021 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include <linux/cpu.h>
24 #include <linux/cpumask.h>
25 #include <asm/processor.h>
26 #include <linux/topology.h>
27 #include <linux/slab.h>
28 
29 #include "lib/assert.h"
30 #include "lib/errno.h"
31 #include "lib/list.h"
32 #include "lib/memory.h"
33 #include "lib/processor.h"
34 
35 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
36 #include "lib/trace.h"
37 
53 #ifdef CONFIG_X86_64
54 enum {
56  DEFAULT_L1_SZ = 32 * 1024,
58  DEFAULT_L2_SZ = 6144 * 1024,
59 
61  PROCESSOR_INTEL_CPUID4_OP = 4,
62 
63  PROCESSOR_INTEL_CTYPE_MASK = 0x1f,
64  PROCESSOR_INTEL_CTYPE_NULL = 0,
65 
66  PROCESSOR_INTEL_CLEVEL_MASK = 0x7,
67  PROCESSOR_INTEL_CLEVEL_SHIFT = 5,
68 
69  PROCESSOR_INTEL_CSHARE_MASK = 0xfff,
70  PROCESSOR_INTEL_CSHARE_SHIFT = 14,
71 
72  PROCESSOR_INTEL_LINESZ_MASK = 0xfff,
73 
74  PROCESSOR_INTEL_PARTITION_MASK = 0x3f,
75  PROCESSOR_INTEL_PARTITION_SHIFT = 12,
76 
77  PROCESSOR_INTEL_ASSOCIATIVITY_MASK = 0x3f,
78  PROCESSOR_INTEL_ASSOCIATIVITY_SHIFT = 22,
79 
80  PROCESSOR_L1_CACHE = 1,
81  PROCESSOR_L2_CACHE = 2,
82 
84  PROCESSOR_AMD_L1_OP = 0x80000005,
85 
86  PROCESSOR_AMD_CSIZE_SHIFT = 24,
87 };
88 
95 struct processor_node {
97  struct m0_list_link pn_link;
98 
101 };
102 
103 /* Global variables */
104 static bool processor_init = false;
105 static struct m0_list x86_cpus;
106 #endif /* CONFIG_X86_64 */
107 
108 #if defined (CONFIG_X86_64) || defined (CONFIG_AARCH64)
109 
121 static void processors_bitmap_copy(struct m0_bitmap *dest,
122  const cpumask_t *src,
123  uint32_t bmpsz)
124 {
125  uint32_t bit;
126  bool val;
127 
128  M0_PRE(dest->b_nr >= bmpsz);
129 
130  for (bit = 0; bit < bmpsz; ++bit) {
131  val = cpumask_test_cpu(bit, src);
132  m0_bitmap_set(dest, bit, val);
133  }
134 }
135 #endif /* (CONFIG_X86_64) || (CONFIG_AARCH64) */
136 
137 #ifdef CONFIG_X86_64
138 
145 static inline uint32_t processor_numanodeid_get(m0_processor_nr_t id)
146 {
147  return cpu_to_node(id);
148 }
149 
158 static inline uint32_t processor_pipelineid_get(m0_processor_nr_t id)
159 {
160  return id;
161 }
162 
171 static size_t processor_cache_sz_get(m0_processor_nr_t id, uint32_t cache_level)
172 {
173  uint32_t sz = 0;
174 
175  switch (cache_level) {
176  case PROCESSOR_L1_CACHE:
177  sz = DEFAULT_L1_SZ;
178  break;
179  case PROCESSOR_L2_CACHE:
180  sz = DEFAULT_L2_SZ;
181  break;
182  default:
183  break;
184  }
185  return sz;
186 }
187 
195 static inline uint32_t processor_x86cache_level_get(uint32_t eax)
196 {
197  return (eax >> PROCESSOR_INTEL_CLEVEL_SHIFT) &
198  PROCESSOR_INTEL_CLEVEL_MASK;
199 }
200 
209 static inline uint32_t processor_x86cache_shares_get(uint32_t eax)
210 {
211  return (eax >> PROCESSOR_INTEL_CSHARE_SHIFT) &
212  PROCESSOR_INTEL_CSHARE_MASK;
213 }
214 
223 static uint32_t processor_x86cache_leaves_get(m0_processor_nr_t id)
224 {
225  uint32_t eax;
226  uint32_t ebx;
227  uint32_t ecx;
228  uint32_t edx;
229  uint32_t cachetype;
230  /*
231  * Assume AMD supports at least L2. For AMD processors this
232  * value is not used later.
233  */
234  uint32_t leaves = 3;
235  int count = -1;
236  struct cpuinfo_x86 *p = &cpu_data(id);
237 
238  if (p->x86_vendor == X86_VENDOR_INTEL) {
239  do {
240  count++;
241  cpuid_count(PROCESSOR_INTEL_CPUID4_OP, count,
242  &eax, &ebx, &ecx, &edx);
243  cachetype = eax & PROCESSOR_INTEL_CTYPE_MASK;
244 
245  } while (cachetype != PROCESSOR_INTEL_CTYPE_NULL);
246  leaves = count;
247  }
248 
249  return leaves;
250 }
251 
262 static uint32_t processor_x86_cacheid_get(m0_processor_nr_t id,
263  uint32_t cache_level,
264  uint32_t cache_leaves)
265 {
266  uint32_t cache_id = id;
267  uint32_t eax;
268  uint32_t ebx;
269  uint32_t ecx;
270  uint32_t edx;
271  uint32_t shares;
272  uint32_t phys;
273  uint32_t core;
274 
275  bool l3_present = false;
276  bool cache_shared_at_core = false;
277 
278  struct cpuinfo_x86 *p = &cpu_data(id);
279 
280  /*
281  * Get L1/L2 cache id for INTEL cpus. If INTEL cpuid level is less
282  * than 4, then use default value.
283  * For AMD cpus, like Linux kernel, assume that L1/L2 is not shared.
284  */
285  if (p->x86_vendor == X86_VENDOR_INTEL &&
286  p->cpuid_level >= PROCESSOR_INTEL_CPUID4_OP &&
287  cache_level < cache_leaves) {
288 
289  cpuid_count(PROCESSOR_INTEL_CPUID4_OP, cache_level,
290  &eax, &ebx, &ecx, &edx);
291  shares = processor_x86cache_shares_get(eax);
292 
293  if (shares > 0) {
294  /*
295  * Check if L3 is present. We assume that if L3 is
296  * present then L2 is shared at core. Otherwise L2 is
297  * shared at physical package level.
298  */
299  if (cache_leaves > 3)
300  l3_present = true;
301  phys = topology_physical_package_id(id);
302  core = topology_core_id(id);
303  switch (cache_level) {
304  case PROCESSOR_L1_CACHE:
305  cache_shared_at_core = true;
306  break;
307  case PROCESSOR_L2_CACHE:
308  if (l3_present)
309  cache_shared_at_core = true;
310  else
311  cache_id = phys;
312  break;
313  default:
314  break;
315  }
316  if (cache_shared_at_core)
317  cache_id = phys << 16 | core;
318  }/* cache is shared */
319 
320  }/* end of if - Intel processor with CPUID4 support */
321 
322  return cache_id;
323 }
324 
333 static uint32_t processor_amd_cache_sz_get(m0_processor_nr_t id,
334  uint32_t cache_level)
335 {
336  uint32_t eax;
337  uint32_t ebx;
338  uint32_t ecx;
339  uint32_t l1;
340  uint32_t sz = 0;
341 
342  struct cpuinfo_x86 *p;
343 
344  switch (cache_level) {
345  case PROCESSOR_L1_CACHE:
346  cpuid(PROCESSOR_AMD_L1_OP, &eax, &ebx, &ecx, &l1);
347  sz = (l1 >> PROCESSOR_AMD_CSIZE_SHIFT) * 1024;
348  break;
349  case PROCESSOR_L2_CACHE:
350  p = &cpu_data(id);
351  sz = p->x86_cache_size;
352  break;
353  default:
354  break;
355  }
356 
357  return sz;
358 }
359 
369 static uint32_t processor_intel_cache_sz_get(m0_processor_nr_t id,
370  uint32_t cache_level)
371 {
372  uint32_t eax;
373  uint32_t ebx;
374  uint32_t ecx;
375  uint32_t edx;
376  uint32_t sets;
377  uint32_t linesz;
378  uint32_t partition;
379  uint32_t asso;
380  uint32_t level;
381  uint32_t sz = 0;
382 
383  bool use_defaults = true;
384  struct cpuinfo_x86 *p = &cpu_data(id);
385 
386  if (p->cpuid_level >= PROCESSOR_INTEL_CPUID4_OP) {
387  cpuid_count(PROCESSOR_INTEL_CPUID4_OP, cache_level,
388  &eax, &ebx, &ecx, &edx);
389  level = processor_x86cache_level_get(eax);
390  if (level == cache_level) {
391  linesz = ebx & PROCESSOR_INTEL_LINESZ_MASK;
392  partition = (ebx >> PROCESSOR_INTEL_PARTITION_SHIFT)
393  & PROCESSOR_INTEL_PARTITION_MASK;
394  asso = (ebx >> PROCESSOR_INTEL_ASSOCIATIVITY_SHIFT)
395  & PROCESSOR_INTEL_ASSOCIATIVITY_MASK;
396  sets = ecx;
397  sz = (linesz+1) * (sets+1) * (partition+1) * (asso+1);
398  use_defaults = false;
399  }
400  }
401 
402  if (use_defaults) {
403  switch (cache_level) {
404  case PROCESSOR_L1_CACHE:
405  sz = DEFAULT_L1_SZ;
406  break;
407  case PROCESSOR_L2_CACHE:
408  sz = DEFAULT_L2_SZ;
409  break;
410  default:
411  break;
412  }
413  }
414 
415  return sz;
416 }
417 
426 static uint32_t processor_x86_cache_sz_get(m0_processor_nr_t id,
427  uint32_t cache_level)
428 {
429  uint32_t sz;
430  struct cpuinfo_x86 *p = &cpu_data(id);
431 
432  switch (p->x86_vendor) {
433  case X86_VENDOR_AMD:
434  /*
435  * Get L1/L2 cache size for AMD processors.
436  */
437  sz = processor_amd_cache_sz_get(id, cache_level);
438  break;
439  case X86_VENDOR_INTEL:
440  /*
441  * Get L1/L2 cache size for INTEL processors.
442  */
443  sz = processor_intel_cache_sz_get(id, cache_level);
444  break;
445  default:
446  /*
447  * Use default function for all other x86 vendors.
448  */
449  sz = processor_cache_sz_get(id, cache_level);
450  break;
451  }/* end of switch - vendor name */
452 
453  return sz;
454 }
455 
464 static void processor_x86_attrs_get(void *arg)
465 {
466  uint32_t c_leaves;
467  m0_processor_nr_t cpu = smp_processor_id();
468  struct processor_node *pinfo = (struct processor_node *) arg;
469 
470  /*
471  * Fetch other generic properties.
472  */
473  pinfo->pn_info.pd_id = cpu;
474  pinfo->pn_info.pd_numa_node = processor_numanodeid_get(cpu);
475  pinfo->pn_info.pd_pipeline = processor_pipelineid_get(cpu);
476 
477  c_leaves = processor_x86cache_leaves_get(cpu);
478  /*
479  * Now fetch the x86 cache information.
480  */
481  pinfo->pn_info.pd_l1 =
482  processor_x86_cacheid_get(cpu, PROCESSOR_L1_CACHE, c_leaves);
483  pinfo->pn_info.pd_l2 =
484  processor_x86_cacheid_get(cpu, PROCESSOR_L2_CACHE, c_leaves);
485 
486  pinfo->pn_info.pd_l1_sz =
487  processor_x86_cache_sz_get(cpu, PROCESSOR_L1_CACHE);
488  pinfo->pn_info.pd_l2_sz =
489  processor_x86_cache_sz_get(cpu, PROCESSOR_L2_CACHE);
490 }
491 
508 static int processor_x86_info_get(m0_processor_nr_t id,
509  struct m0_processor_descr *pd)
510 {
511  struct processor_node *pinfo;
512 
513  M0_PRE(pd != NULL);
515 
516  m0_list_for_each_entry(&x86_cpus, pinfo, struct processor_node,
517  pn_link) {
518  if (pinfo->pn_info.pd_id == id) {
519  *pd = pinfo->pn_info;
520  return 0;
521  }/* if - matching CPU id found */
522 
523  }/* for - iterate over all the processor nodes */
524 
525  return M0_ERR(-EINVAL);
526 }
527 
534 static void processor_x86cache_destroy(void)
535 {
536  struct m0_list_link *node;
537  struct processor_node *pinfo;
538 
539  /*
540  * Remove all the processor nodes.
541  */
542  node = x86_cpus.l_head;
543  while((struct m0_list *)node != &x86_cpus) {
545  m0_list_del(&pinfo->pn_link);
546  m0_free(pinfo);
547  node = x86_cpus.l_head;
548  }
549  m0_list_fini(&x86_cpus);
550 }
551 
560 static int processor_x86cache_create(void)
561 {
562  uint32_t cpu;
563  struct processor_node *pinfo;
564 
565  m0_list_init(&x86_cpus);
566 
567  /*
568  * Using online CPU mask get details of each processor.
569  * Unless CPU is online, we cannot execute on it.
570  */
571  for_each_online_cpu(cpu) {
573  if (pinfo == NULL) {
574  processor_x86cache_destroy();
575  return M0_ERR(-ENOMEM);
576  }
577 
578  /*
579  * We may not be running on the same processor for which cache
580  * info is needed. Hence run the function on the requested
581  * processor. smp_call... has all the optimization necessary.
582  */
583  smp_call_function_single(cpu, processor_x86_attrs_get,
584  (void *)pinfo, true);
585  m0_list_add(&x86_cpus, &pinfo->pn_link);
586  }/* for - scan all the online processors */
587 
588  if (m0_list_is_empty(&x86_cpus)) {
589  m0_list_fini(&x86_cpus);
590  return M0_ERR(-ENODATA);
591  }
592 
593  return 0;
594 }
595 #endif /* CONFIG_X86_64 */
596 
597 #if defined (CONFIG_X86_64) || defined (CONFIG_AARCH64)
598 M0_INTERNAL int m0_processors_init()
599 {
600 #ifdef CONFIG_X86_64
601  int rc;
602 
604  rc = processor_x86cache_create();
605  processor_init = (rc == 0);
606  return M0_RC(rc);
607 #elif defined (CONFIG_AARCH64)
608  return 0;
609 #endif
610 }
611 
612 M0_INTERNAL void m0_processors_fini()
613 {
614 #ifdef CONFIG_X86_64
616  processor_x86cache_destroy();
617  processor_init = false;
618 #elif defined (CONFIG_AARCH64)
619 #endif
620 }
621 
622 M0_INTERNAL m0_processor_nr_t m0_processor_nr_max(void)
623 {
624  return NR_CPUS;
625 }
626 
627 M0_INTERNAL void m0_processors_possible(struct m0_bitmap *map)
628 {
629  processors_bitmap_copy(map, cpu_possible_mask, nr_cpu_ids);
630 }
631 
632 M0_INTERNAL void m0_processors_available(struct m0_bitmap *map)
633 {
634  processors_bitmap_copy(map, cpu_present_mask, nr_cpu_ids);
635 }
636 
637 M0_INTERNAL void m0_processors_online(struct m0_bitmap *map)
638 {
639  processors_bitmap_copy(map, cpu_online_mask, nr_cpu_ids);
640 }
641 
642 #ifdef CONFIG_X86_64
643 M0_INTERNAL int m0_processor_describe(m0_processor_nr_t id,
644  struct m0_processor_descr *pd)
645 {
646  M0_PRE(pd != NULL);
647  if (id >= nr_cpu_ids)
648  return M0_ERR(-EINVAL);
649 
650  return processor_x86_info_get(id, pd);
651 }
652 #endif /* CONFIG_X86_64 */
653 
654 M0_INTERNAL m0_processor_nr_t m0_processor_id_get(void)
655 {
656  return smp_processor_id();
657 }
658 
659 #endif /* CONFIG_X86_64 || CONFIG_AARCH64 */
660 
661 #undef M0_TRACE_SUBSYSTEM
662 
665 /*
666  * Local variables:
667  * c-indentation-style: "K&R"
668  * c-basic-offset: 8
669  * tab-width: 8
670  * fill-column: 80
671  * scroll-step: 1
672  * End:
673  */
uint64_t id
Definition: cob.h:2380
static struct m0_addb2_philter p
Definition: consumer.c:40
#define M0_PRE(cond)
M0_INTERNAL void m0_list_add(struct m0_list *head, struct m0_list_link *new)
Definition: list.c:113
#define NULL
Definition: misc.h:38
map
Definition: processor.c:112
Definition: idx_mock.c:52
M0_INTERNAL void m0_processors_possible(struct m0_bitmap *map)
Definition: processor.c:1099
M0_INTERNAL void m0_list_init(struct m0_list *head)
Definition: list.c:29
enum m0_trace_level level
Definition: trace.c:111
M0_INTERNAL m0_processor_nr_t m0_processor_nr_max(void)
Definition: processor.c:1093
static struct net_test_cmd_node * node
Definition: commands.c:72
M0_INTERNAL void m0_list_fini(struct m0_list *head)
Definition: list.c:36
M0_INTERNAL void m0_list_del(struct m0_list_link *old)
Definition: list.c:147
M0_INTERNAL void m0_processors_fini(void)
Definition: processor.c:1084
struct m0_processor_descr pn_info
Definition: processor.c:153
M0_INTERNAL m0_processor_nr_t m0_processor_id_get(void)
Definition: processor.c:1139
static uint64_t core[NR]
Definition: locality.c:41
static m0_bcount_t count
Definition: xcode.c:167
return M0_RC(rc)
return M0_ERR(-EOPNOTSUPP)
struct m0_list_link pn_link
Definition: processor.c:150
uint32_t m0_processor_nr_t
Definition: processor.h:62
#define m0_list_for_each_entry(head, pos, type, member)
Definition: list.h:235
M0_INTERNAL int m0_processors_init(void)
Definition: processor.c:1062
static uint32_t processor_pipelineid_get(m0_processor_nr_t id)
Definition: processor.c:724
static uint32_t processor_numanodeid_get(m0_processor_nr_t id)
Definition: processor.c:332
M0_INTERNAL void m0_processors_online(struct m0_bitmap *map)
Definition: processor.c:1113
static bool processor_init
Definition: processor.c:180
M0_INTERNAL void m0_bitmap_set(struct m0_bitmap *map, size_t idx, bool val)
Definition: bitmap.c:139
M0_INTERNAL bool m0_list_is_empty(const struct m0_list *head)
Definition: list.c:42
Definition: list.h:72
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
M0_INTERNAL int m0_processor_describe(m0_processor_nr_t id, struct m0_processor_descr *pd)
Definition: processor.c:1120
void m0_free(void *data)
Definition: memory.c:146
struct m0_pdclust_src_addr src
Definition: fd.c:108
int32_t rc
Definition: trigger_fop.h:47
#define m0_list_entry(link, type, member)
Definition: list.h:217
M0_INTERNAL void m0_processors_available(struct m0_bitmap *map)
Definition: processor.c:1106