File indexing completed on 2025-05-11 08:23:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <assert.h>
0037 #include <string.h>
0038
0039 #include <rtems.h>
0040
0041 #include <libcpu/powerpc-utility.h>
0042
0043 #include <bspopts.h>
0044 #include <bsp/irq.h>
0045 #include <bsp/qoriq.h>
0046 #include <bsp/intercom.h>
0047
0048 #ifndef QORIQ_IS_HYPERVISOR_GUEST
0049
0050 #define INTERCOM_EVENT_IPI RTEMS_EVENT_13
0051 #define INTERCOM_EVENT_WAKE_UP RTEMS_EVENT_14
0052
0053 #define PACKET_SIZE_COUNT 4
0054
0055 #define ONE_CORE(core) (1U << (core))
0056 #define ALL_CORES ((1U << INTERCOM_CORE_COUNT) - 1U)
0057 #define OTHER_CORES(core) (ALL_CORES & ~ONE_CORE(core))
0058
0059 #define IPI_INDEX 0
0060
0061 typedef struct consumer {
0062 struct consumer *next;
0063 rtems_id task;
0064 } consumer;
0065
0066 typedef struct {
0067 consumer *head;
0068 uint32_t cache_line_alignment [7];
0069 } consumer_list;
0070
0071 typedef struct {
0072 uint32_t lock;
0073 intercom_packet *head;
0074 size_t size;
0075 uint32_t cores_to_notify;
0076 uint32_t cache_line_alignment [4];
0077 consumer_list waiting_consumers [INTERCOM_CORE_COUNT];
0078 } free_list;
0079
0080 typedef struct {
0081 uint32_t lock;
0082 intercom_packet *head;
0083 intercom_packet *tail;
0084 uint32_t cache_line_alignment [5];
0085 } core_fifo;
0086
0087 typedef struct {
0088 free_list free_lists [PACKET_SIZE_COUNT];
0089 core_fifo core_fifos [INTERCOM_CORE_COUNT];
0090 intercom_service services [INTERCOM_CORE_COUNT][INTERCOM_SERVICE_COUNT];
0091 void *service_args [INTERCOM_CORE_COUNT][INTERCOM_SERVICE_COUNT];
0092 uint32_t ready_lock;
0093 uint32_t ready;
0094 uint32_t cache_line_alignment [6];
0095 } control;
0096
0097 static control *const intercom = (control *) QORIQ_INTERCOM_AREA_BEGIN;
0098
0099 static const size_t packet_sizes [PACKET_SIZE_COUNT] = {
0100 64,
0101 512,
0102 2048,
0103 4096
0104 };
0105
0106 static void send_event(rtems_id task, rtems_event_set event)
0107 {
0108 rtems_status_code sc = RTEMS_SUCCESSFUL;
0109
0110 sc = rtems_event_send(task, event);
0111 assert(sc == RTEMS_SUCCESSFUL);
0112 }
0113
0114 static void wait_for_event(rtems_event_set in)
0115 {
0116 rtems_status_code sc = RTEMS_SUCCESSFUL;
0117 rtems_event_set out;
0118
0119 sc = rtems_event_receive(
0120 in,
0121 RTEMS_EVENT_ALL | RTEMS_WAIT,
0122 RTEMS_NO_TIMEOUT,
0123 &out
0124 );
0125 assert(sc == RTEMS_SUCCESSFUL);
0126 }
0127
0128 static void intercom_handler(void *arg)
0129 {
0130 rtems_id task = (rtems_id) (uintptr_t) arg;
0131 send_event(task, INTERCOM_EVENT_IPI);
0132 }
0133
0134 static void notify_core_by_index(int core)
0135 {
0136 uint32_t self = ppc_processor_id();
0137 qoriq.pic.per_cpu [self].ipidr [IPI_INDEX].reg = ONE_CORE(core);
0138 }
0139
0140 static void notify_cores(uint32_t cores)
0141 {
0142 uint32_t self = ppc_processor_id();
0143 qoriq.pic.per_cpu [self].ipidr [IPI_INDEX].reg = cores;
0144 }
0145
0146 void qoriq_intercom_free_packet(intercom_packet *packet)
0147 {
0148 free_list *list = &intercom->free_lists [packet->size_index];
0149
0150 uint32_t msr = qoriq_spin_lock(&list->lock);
0151 intercom_packet *first = list->head;
0152 list->head = packet;
0153 packet->glue.next = first;
0154 uint32_t cores = list->cores_to_notify;
0155 if (cores != 0) {
0156 list->cores_to_notify = 0;
0157 notify_cores(cores);
0158 }
0159 qoriq_spin_unlock(&list->lock, msr);
0160 }
0161
0162 static void default_service(intercom_packet *packet, void *arg)
0163 {
0164 qoriq_intercom_free_packet(packet);
0165 }
0166
0167 static void process_free_lists(free_list *free_lists, uint32_t self)
0168 {
0169 int i = 0;
0170
0171 for (i = 0; i < PACKET_SIZE_COUNT; ++i) {
0172 free_list *list = &free_lists [i];
0173
0174 uint32_t msr = qoriq_spin_lock(&list->lock);
0175 consumer *waiting_consumer = list->waiting_consumers [self].head;
0176 list->waiting_consumers [self].head = NULL;
0177 qoriq_spin_unlock(&list->lock, msr);
0178
0179 while (waiting_consumer != NULL) {
0180 send_event(waiting_consumer->task, INTERCOM_EVENT_WAKE_UP);
0181 waiting_consumer = waiting_consumer->next;
0182 }
0183 }
0184 }
0185
0186 static void process_core_fifo(core_fifo *fifo, intercom_service *services, void **service_args)
0187 {
0188 uint32_t msr = qoriq_spin_lock(&fifo->lock);
0189 intercom_packet *packet = fifo->head;
0190 fifo->head = NULL;
0191 qoriq_spin_unlock(&fifo->lock, msr);
0192
0193 while (packet != NULL) {
0194 intercom_packet *current = packet;
0195 intercom_type type_index = current->type_index;
0196 packet = current->glue.next;
0197 (*services [type_index])(current, service_args [type_index]);
0198 }
0199 }
0200
0201 static void intercom_task(rtems_task_argument arg)
0202 {
0203 uint32_t self = ppc_processor_id();
0204 free_list *free_lists = &intercom->free_lists [0];
0205 intercom_service *services = &intercom->services [self][0];
0206 void **service_args = &intercom->service_args [self][0];
0207 core_fifo *fifo = &intercom->core_fifos [self];
0208
0209 while (true) {
0210 process_free_lists(free_lists, self);
0211 process_core_fifo(fifo, services, service_args);
0212 wait_for_event(INTERCOM_EVENT_IPI);
0213 }
0214 }
0215
0216 static intercom_packet *free_list_and_packet_init(
0217 free_list *list,
0218 size_t count,
0219 intercom_packet *current,
0220 intercom_size size_index,
0221 size_t size
0222 )
0223 {
0224 intercom_packet *last = current;
0225 size_t inc = 1 + size / sizeof(*current);
0226 size_t i = 0;
0227
0228 assert(count > 0);
0229 assert(size % sizeof(*current) == 0);
0230
0231 list->size = size;
0232 list->head = current;
0233 for (i = 0; i < count; ++i) {
0234 intercom_packet *next = current + inc;
0235 current->glue.next = next;
0236 current->size_index = size_index;
0237 last = current;
0238 current = next;
0239 }
0240 last->glue.next = NULL;
0241
0242 return current;
0243 }
0244
0245 static void basic_init(void)
0246 {
0247 char *begin = (char *) QORIQ_INTERCOM_AREA_BEGIN;
0248 size_t size = QORIQ_INTERCOM_AREA_SIZE;
0249 int i = 0;
0250
0251 memset(begin, 0, size);
0252
0253 assert(size % packet_sizes [PACKET_SIZE_COUNT - 1] == 0);
0254
0255
0256 size_t data_sizes [PACKET_SIZE_COUNT];
0257 data_sizes [PACKET_SIZE_COUNT - 1] = size / 2;
0258 for (i = PACKET_SIZE_COUNT - 2; i > 0; --i) {
0259 data_sizes [i] = data_sizes [i + 1] / 2;
0260 }
0261 data_sizes [i] = data_sizes [i + 1];
0262
0263
0264 size_t packet_counts [PACKET_SIZE_COUNT];
0265 size_t count = 0;
0266 for (i = 1; i < PACKET_SIZE_COUNT; ++i) {
0267 packet_counts [i] = data_sizes [i] / packet_sizes [i];
0268 count += packet_counts [i];
0269 }
0270 packet_counts [0] = (data_sizes [0] - sizeof(control) - count * sizeof(intercom_packet))
0271 / (sizeof(intercom_packet) + packet_sizes [0]);
0272
0273
0274 intercom_packet *packet = (intercom_packet *) (begin + sizeof(control));
0275 for (i = 0; i < PACKET_SIZE_COUNT; ++i) {
0276 packet = free_list_and_packet_init(
0277 &intercom->free_lists [i],
0278 packet_counts [i],
0279 packet,
0280 i,
0281 packet_sizes [i]
0282 );
0283 }
0284
0285 rtems_cache_flush_multiple_data_lines(begin, size);
0286 ppc_synchronize_data();
0287 }
0288
0289 static void services_init(uint32_t self)
0290 {
0291 int i = 0;
0292
0293 for (i = 0; i < INTERCOM_SERVICE_COUNT; ++i) {
0294 if (intercom->services [self][i] == NULL) {
0295 intercom->services [self][i] = default_service;
0296 }
0297 }
0298 }
0299
0300 void qoriq_intercom_init(void)
0301 {
0302 rtems_status_code sc = RTEMS_SUCCESSFUL;
0303 rtems_id task = RTEMS_ID_NONE;
0304 uint32_t self = ppc_processor_id();
0305
0306 sc = rtems_task_create(
0307 rtems_build_name('I', 'C', 'O', 'M'),
0308 10,
0309 0,
0310 RTEMS_DEFAULT_MODES,
0311 RTEMS_DEFAULT_ATTRIBUTES,
0312 &task
0313 );
0314 assert(sc == RTEMS_SUCCESSFUL);
0315
0316 sc = rtems_interrupt_set_priority(
0317 QORIQ_IRQ_IPI_0,
0318 QORIQ_PIC_PRIORITY_LOWEST
0319 );
0320 assert(sc == RTEMS_SUCCESSFUL);
0321
0322 sc = rtems_interrupt_handler_install(
0323 QORIQ_IRQ_IPI_0,
0324 "INTERCOM",
0325 RTEMS_INTERRUPT_UNIQUE,
0326 intercom_handler,
0327 (void *) (uintptr_t) task
0328 );
0329 assert(sc == RTEMS_SUCCESSFUL);
0330
0331 if (self == 0) {
0332 basic_init();
0333 }
0334
0335 services_init(self);
0336
0337 sc = rtems_task_start(task, intercom_task, 0);
0338 assert(sc == RTEMS_SUCCESSFUL);
0339 }
0340
0341 void qoriq_intercom_start(void)
0342 {
0343 uint32_t self = ppc_processor_id();
0344 uint32_t ready = 0;
0345
0346 while (ready != ALL_CORES) {
0347 uint32_t msr = qoriq_spin_lock(&intercom->ready_lock);
0348 ready = intercom->ready;
0349 intercom->ready = ready | ONE_CORE(self);
0350 qoriq_spin_unlock(&intercom->ready_lock, msr);
0351 }
0352 }
0353
0354 static intercom_packet *allocate(intercom_type type, free_list *list)
0355 {
0356 uint32_t self = ppc_processor_id();
0357 intercom_packet *packet = NULL;
0358 consumer poor = {
0359 .task = rtems_task_self()
0360 };
0361
0362 while (packet == NULL) {
0363 uint32_t msr = qoriq_spin_lock(&list->lock);
0364 packet = list->head;
0365 if (packet != NULL) {
0366 list->head = packet->glue.next;
0367 } else {
0368 consumer *first = list->waiting_consumers [self].head;
0369 list->waiting_consumers [self].head = &poor;
0370 poor.next = first;
0371 if (first == NULL) {
0372 list->cores_to_notify |= ONE_CORE(self);
0373 }
0374 }
0375 qoriq_spin_unlock(&list->lock, msr);
0376
0377 if (packet == NULL) {
0378 wait_for_event(INTERCOM_EVENT_WAKE_UP);
0379 }
0380 }
0381
0382 packet->glue.next = NULL;
0383 packet->type_index = type;
0384 packet->flags = 0;
0385 packet->size = list->size;
0386
0387 return packet;
0388 }
0389
0390 intercom_packet *qoriq_intercom_allocate_packet(intercom_type type, intercom_size size)
0391 {
0392 assert((unsigned) type < INTERCOM_SERVICE_COUNT);
0393 assert((unsigned) size < PACKET_SIZE_COUNT);
0394
0395 return allocate(type, &intercom->free_lists [size]);
0396 }
0397
0398 void qoriq_intercom_send_packets(int destination_core, intercom_packet *first, intercom_packet *last)
0399 {
0400 assert(destination_core >= 0);
0401 assert(destination_core < INTERCOM_CORE_COUNT);
0402
0403 core_fifo *fifo = &intercom->core_fifos [destination_core];
0404
0405 uint32_t msr = qoriq_spin_lock(&fifo->lock);
0406 last->glue.next = NULL;
0407 if (fifo->head != NULL) {
0408 fifo->tail->glue.next = first;
0409 } else {
0410 fifo->head = first;
0411 notify_core_by_index(destination_core);
0412 }
0413 fifo->tail = last;
0414 qoriq_spin_unlock(&fifo->lock, msr);
0415 }
0416
0417 void qoriq_intercom_broadcast_packets(intercom_packet *first, intercom_packet *last)
0418 {
0419 int i = 0;
0420
0421 for (i = 1; i < INTERCOM_CORE_COUNT; ++i) {
0422 intercom_packet *clone_first = NULL;
0423 intercom_packet *clone_last = NULL;
0424
0425 intercom_packet *current = first;
0426 while (current != NULL) {
0427 intercom_packet *clone = qoriq_intercom_clone_packet(current);
0428 if (clone_first == NULL) {
0429 clone_first = clone;
0430 }
0431 if (clone_last != NULL) {
0432 clone_last->glue.next = clone;
0433 }
0434 clone_last = clone;
0435 current = current->glue.next;
0436 }
0437
0438 qoriq_intercom_send_packets(i, clone_first, clone_last);
0439 }
0440
0441 qoriq_intercom_send_packets(0, first, last);
0442 }
0443
0444 void qoriq_intercom_send(int destination_core, intercom_type type, intercom_size size, const void *buf, size_t n)
0445 {
0446 assert((unsigned) size < PACKET_SIZE_COUNT);
0447
0448 size_t remaining = n;
0449 size_t packet_size = packet_sizes [size];
0450 const char *src = buf;
0451 intercom_packet *first = NULL;
0452 intercom_packet *last = NULL;
0453
0454 do {
0455 intercom_packet *packet = qoriq_intercom_allocate_packet(
0456 type,
0457 size
0458 );
0459 if (first == NULL) {
0460 first = packet;
0461 }
0462 if (last != NULL) {
0463 last->glue.next = packet;
0464 }
0465 last = packet;
0466 size_t current_size = remaining < packet_size ? remaining : packet_size;
0467 remaining -= current_size;
0468 packet->size = current_size;
0469 const char *current = src;
0470 src += current_size;
0471 memcpy(packet->data, current, current_size);
0472 } while (remaining > 0);
0473
0474 qoriq_intercom_send_packets(destination_core, first, last);
0475 }
0476
0477 void qoriq_intercom_service_install(intercom_type type, intercom_service service, void *arg)
0478 {
0479 assert((unsigned) type < INTERCOM_SERVICE_COUNT);
0480
0481 uint32_t self = ppc_processor_id();
0482 intercom->service_args [self][type] = arg;
0483 ppc_enforce_in_order_execution_of_io();
0484 intercom->services [self][type] = service;
0485 }
0486
0487 void qoriq_intercom_service_remove(intercom_type type)
0488 {
0489 assert((unsigned) type < INTERCOM_SERVICE_COUNT);
0490
0491 uint32_t self = ppc_processor_id();
0492 intercom->services [self][type] = default_service;
0493 ppc_enforce_in_order_execution_of_io();
0494 intercom->service_args [self][type] = NULL;
0495 }
0496
0497 intercom_packet *qoriq_intercom_clone_packet(const intercom_packet *packet)
0498 {
0499 intercom_packet *clone = qoriq_intercom_allocate_packet(
0500 packet->type_index,
0501 packet->size_index
0502 );
0503
0504 clone->size = packet->size;
0505 memcpy(clone->data, packet->data, clone->size);
0506
0507 return clone;
0508 }
0509
0510 #endif