source: rtems/bsps/powerpc/qoriq/start/bspsmp.c @ 0d362ff3

5
Last change on this file since 0d362ff3 was 0d362ff3, checked in by Sebastian Huber <sebastian.huber@…>, on 07/23/18 at 12:54:51

score: _SMP_Inter_processor_interrupt_handler()

Pass current processor control via parameter since it may be already
available at the caller side.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Copyright (c) 2013, 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <rtems/score/smpimpl.h>
16
17#include <libfdt.h>
18
19#include <libcpu/powerpc-utility.h>
20
21#include <bsp.h>
22#include <bsp/fdt.h>
23#include <bsp/mmu.h>
24#include <bsp/fatal.h>
25#include <bsp/qoriq.h>
26#include <bsp/vectors.h>
27#include <bsp/bootcard.h>
28#include <bsp/irq-generic.h>
29#include <bsp/linker-symbols.h>
30
31LINKER_SYMBOL(bsp_exc_vector_base);
32
33#if QORIQ_THREAD_COUNT > 1
34void _start_thread(void);
35#endif
36
37void _start_secondary_processor(void);
38
39#define IPI_INDEX 0
40
41#if QORIQ_THREAD_COUNT > 1
42static bool is_started_by_u_boot(uint32_t cpu_index)
43{
44  return cpu_index % QORIQ_THREAD_COUNT == 0;
45}
46
47void qoriq_start_thread(void)
48{
49  const Per_CPU_Control *cpu_self = _Per_CPU_Get();
50
51  ppc_exc_initialize_interrupt_stack(
52    (uintptr_t) cpu_self->interrupt_stack_low,
53    rtems_configuration_get_interrupt_stack_size()
54  );
55
56  bsp_interrupt_facility_initialize();
57
58  _SMP_Start_multitasking_on_secondary_processor();
59}
60#endif
61
62static void start_thread_if_necessary(uint32_t cpu_index_self)
63{
64#if QORIQ_THREAD_COUNT > 1
65  uint32_t i;
66
67  for (i = 1; i < QORIQ_THREAD_COUNT; ++i) {
68    uint32_t cpu_index_next = cpu_index_self + i;
69
70    if (
71      is_started_by_u_boot(cpu_index_self)
72        && cpu_index_next < rtems_configuration_get_maximum_processors()
73        && _SMP_Should_start_processor(cpu_index_next)
74    ) {
75      /* Thread Initial Next Instruction Address (INIA) */
76      PPC_SET_THREAD_MGMT_REGISTER(321, (uintptr_t) _start_thread);
77
78      /* Thread Initial Machine State (IMSR) */
79      PPC_SET_THREAD_MGMT_REGISTER(289, QORIQ_INITIAL_MSR);
80
81      /* Thread Enable Set (TENS) */
82      PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_TENS, 1U << i);
83    }
84  }
85#endif
86}
87
88void bsp_start_on_secondary_processor(void)
89{
90  uint32_t cpu_index_self = _SMP_Get_current_processor();
91  const Per_CPU_Control *cpu_self = _Per_CPU_Get_by_index(cpu_index_self);
92
93  qoriq_initialize_exceptions(cpu_self->interrupt_stack_low);
94  bsp_interrupt_facility_initialize();
95
96  start_thread_if_necessary(cpu_index_self);
97
98  _SMP_Start_multitasking_on_secondary_processor();
99}
100
101#ifndef QORIQ_IS_HYPERVISOR_GUEST
102static void bsp_inter_processor_interrupt(void *arg)
103{
104  _SMP_Inter_processor_interrupt_handler(_Per_CPU_Get());
105}
106#endif
107
108static void setup_boot_page(void)
109{
110#ifdef QORIQ_IS_HYPERVISOR_GUEST
111  qoriq_mmu_context mmu_context;
112
113  qoriq_mmu_context_init(&mmu_context);
114  qoriq_mmu_add(
115    &mmu_context,
116    0xfffff000,
117    0xffffffff,
118    0,
119    0,
120    FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
121    0
122  );
123  qoriq_mmu_partition(&mmu_context, 1);
124  qoriq_mmu_write_to_tlb1(&mmu_context, QORIQ_TLB1_ENTRY_COUNT - 1);
125#endif
126}
127
128static uint32_t discover_processors(void)
129{
130  const void *fdt = bsp_fdt_get();
131  int cpus = fdt_path_offset(fdt, "/cpus");
132  int node = fdt_first_subnode(fdt, cpus);
133  uint32_t cpu = 0;
134
135  while (node >= 0 && cpu < RTEMS_ARRAY_SIZE(qoriq_start_spin_table_addr)) {
136    int len;
137    fdt64_t *addr_fdt = (fdt64_t *)
138      fdt_getprop(fdt, node, "cpu-release-addr", &len);
139
140    if (addr_fdt != NULL) {
141      uintptr_t addr = (uintptr_t) fdt64_to_cpu(*addr_fdt);
142
143      qoriq_start_spin_table_addr[cpu] = (qoriq_start_spin_table *) addr;
144    }
145
146    ++cpu;
147    node = fdt_next_subnode(fdt, node);
148  }
149
150  return cpu * QORIQ_THREAD_COUNT;
151}
152
153uint32_t _CPU_SMP_Initialize(void)
154{
155  uint32_t cpu_count = 1;
156
157  if (rtems_configuration_get_maximum_processors() > 0) {
158    setup_boot_page();
159    cpu_count = discover_processors();
160  }
161
162  start_thread_if_necessary(0);
163
164  return cpu_count;
165}
166
167static bool release_processor(
168  qoriq_start_spin_table *spin_table,
169  uint32_t cpu_index
170)
171{
172  bool spin_table_present = (spin_table != NULL);
173
174  if (spin_table_present) {
175    const Per_CPU_Control *cpu = _Per_CPU_Get_by_index(cpu_index);
176
177    spin_table->pir = cpu_index;
178    spin_table->r3 = (uintptr_t) cpu->interrupt_stack_high;
179    rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
180    ppc_synchronize_data();
181    spin_table->addr = (uintptr_t) _start_secondary_processor;
182    rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
183  }
184
185  return spin_table_present;
186}
187
188static qoriq_start_spin_table *get_spin_table(uint32_t cpu_index)
189{
190  qoriq_start_spin_table *spin_table;
191
192  spin_table = qoriq_start_spin_table_addr[cpu_index / QORIQ_THREAD_COUNT];
193
194  return spin_table;
195}
196
197bool _CPU_SMP_Start_processor(uint32_t cpu_index)
198{
199#if QORIQ_THREAD_COUNT > 1
200  if (is_started_by_u_boot(cpu_index)) {
201    qoriq_start_spin_table *spin_table = get_spin_table(cpu_index);
202
203    return release_processor(spin_table, cpu_index);
204  } else {
205    return _SMP_Should_start_processor(cpu_index - 1);
206  }
207#else
208  qoriq_start_spin_table *spin_table = get_spin_table(cpu_index);
209
210  return release_processor(spin_table, cpu_index);
211#endif
212}
213
214void _CPU_SMP_Finalize_initialization(uint32_t cpu_count)
215{
216#ifdef QORIQ_IS_HYPERVISOR_GUEST
217  (void) cpu_count;
218#else
219  if (cpu_count > 1) {
220    rtems_status_code sc;
221
222    sc = rtems_interrupt_handler_install(
223      QORIQ_IRQ_IPI_0 + IPI_INDEX,
224      "IPI",
225      RTEMS_INTERRUPT_UNIQUE,
226      bsp_inter_processor_interrupt,
227      NULL
228    );
229    if (sc != RTEMS_SUCCESSFUL) {
230      bsp_fatal(QORIQ_FATAL_SMP_IPI_HANDLER_INSTALL);
231    }
232  }
233#endif
234}
235
236void _CPU_SMP_Prepare_start_multitasking(void)
237{
238  /* Do nothing */
239}
240
241void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
242{
243#ifdef QORIQ_IS_HYPERVISOR_GUEST
244  uint32_t msg;
245
246  /* DBELL message type */
247  msg = (0U << (63 - 36)) | target_processor_index;
248  __asm__ volatile ("msgsnd %0" : : "r" (msg));
249#else
250  qoriq.pic.ipidr [IPI_INDEX].reg = 1U << target_processor_index;
251#endif
252}
Note: See TracBrowser for help on using the repository browser.