Skip to content

Commit 26c8dcc

Browse files
committed
Use mutex to ensure segment update and CRA read/write happens atomically
When multiple threads may access the kernel CRA registers and there are enough kernel that segment register may be modified throughout the run, we need to ensure there is no more additional segment updates coming in between a segment update and consequent CRA read/write.
1 parent a2b4e41 commit 26c8dcc

File tree

2 files changed

+111
-66
lines changed

2 files changed

+111
-66
lines changed

include/acl_kernel_if.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "acl_hal.h"
1313
#include "acl_types.h"
1414

15+
#include <mutex>
1516
#include <optional>
1617
#include <string>
1718
#include <vector>
@@ -60,6 +61,12 @@ typedef struct {
6061

6162
acl_bsp_io io;
6263

64+
// Acquired when any thread is trying to perform CRA non-ROM read or write.
65+
// This is to ensure that CRA segment register write happens concurrently
66+
// with the subsequent data read or write, so the data read or write goes
67+
// to the CRA of the intended kernel.
68+
std::mutex segment_mutex;
69+
6370
// csr_version is absent if there is no accelerators or cra_ring_root doesn't
6471
// exist
6572
std::optional<unsigned int> csr_version;

src/acl_kernel_if.cpp

Lines changed: 104 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -400,20 +400,42 @@ static uintptr_t acl_kernel_cra_set_segment_rom(acl_kernel_if *kern,
400400

401401
static int acl_kernel_cra_read(acl_kernel_if *kern, unsigned int accel_id,
402402
unsigned int addr, unsigned int *val) {
403+
int result = 0;
403404
assert(kern->cra_ring_root_exist);
404-
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
405-
acl_assert_locked_or_sig();
406-
return acl_kernel_if_read_32b(
407-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
405+
#ifdef __linux__
406+
acl_sig_block_signals();
407+
#endif
408+
{
409+
std::lock_guard<std::mutex> lock(kern->segment_mutex);
410+
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
411+
acl_assert_locked_or_sig();
412+
result = acl_kernel_if_read_32b(
413+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
414+
}
415+
#ifdef __linux__
416+
acl_sig_unblock_signals();
417+
#endif
418+
return result;
408419
}
409420

410421
int acl_kernel_cra_read_64b(acl_kernel_if *kern, unsigned int accel_id,
411422
unsigned int addr, uint64_t *val) {
423+
int result = 0;
412424
assert(kern->cra_ring_root_exist);
413-
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
414-
acl_assert_locked_or_sig();
415-
return acl_kernel_if_read_64b(
416-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
425+
#ifdef __linux__
426+
acl_sig_block_signals();
427+
#endif
428+
{
429+
std::lock_guard<std::mutex> lock(kern->segment_mutex);
430+
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
431+
acl_assert_locked_or_sig();
432+
result = acl_kernel_if_read_64b(
433+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
434+
}
435+
#ifdef __linux__
436+
acl_sig_unblock_signals();
437+
#endif
438+
return result;
417439
}
418440

419441
// Read 32b from kernel ROM
@@ -461,61 +483,95 @@ static int acl_kernel_rom_cra_read_block(acl_kernel_if *kern, unsigned int addr,
461483

462484
static int acl_kernel_cra_write(acl_kernel_if *kern, unsigned int accel_id,
463485
unsigned int addr, unsigned int val) {
486+
int result = 0;
464487
assert(kern->cra_ring_root_exist);
465-
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
466-
acl_assert_locked_or_sig();
467-
return acl_kernel_if_write_32b(
468-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
488+
#ifdef __linux__
489+
acl_sig_block_signals();
490+
#endif
491+
{
492+
std::lock_guard<std::mutex> lock(kern->segment_mutex);
493+
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
494+
acl_assert_locked_or_sig();
495+
result = acl_kernel_if_write_32b(
496+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
497+
}
498+
#ifdef __linux__
499+
acl_sig_unblock_signals();
500+
#endif
501+
return result;
469502
}
470503

471504
static int acl_kernel_cra_write_64b(acl_kernel_if *kern, unsigned int accel_id,
472505
unsigned int addr, uint64_t val) {
506+
int result = 0;
473507
assert(kern->cra_ring_root_exist);
474-
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
475-
acl_assert_locked();
476-
return acl_kernel_if_write_64b(
477-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
508+
#ifdef __linux__
509+
acl_sig_block_signals();
510+
#endif
511+
{
512+
std::lock_guard<std::mutex> lock(kern->segment_mutex);
513+
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
514+
acl_assert_locked();
515+
result = acl_kernel_if_write_64b(
516+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val);
517+
}
518+
#ifdef __linux__
519+
acl_sig_unblock_signals();
520+
#endif
521+
return result;
478522
}
479523

480524
static int acl_kernel_cra_write_block(acl_kernel_if *kern,
481525
unsigned int accel_id, unsigned int addr,
482526
unsigned int *val, size_t size) {
527+
int result = 0;
483528
assert(kern->cra_ring_root_exist);
484-
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
485-
uintptr_t logical_addr =
486-
kern->accel_csr[accel_id].address + addr - OFFSET_KERNEL_CRA;
487-
uintptr_t segment = logical_addr & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
488-
489-
uintptr_t logical_addr_end =
490-
kern->accel_csr[accel_id].address + addr + size - OFFSET_KERNEL_CRA;
491-
uintptr_t segment_end =
492-
logical_addr_end & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
493-
494-
unsigned int step = 0;
495-
if (segment != segment_end) {
496-
ACL_KERNEL_IF_DEBUG_MSG_VERBOSE(
497-
kern, 2, ":: Segment change during block write detected.\n");
498-
while (step < size) {
499-
segment = (logical_addr + step) & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
500-
if (kern->cur_segment != segment) {
501-
acl_kernel_if_write_block(
502-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val,
503-
step);
504-
segment_offset =
505-
acl_kernel_cra_set_segment(kern, accel_id, addr + step);
506-
logical_addr =
507-
kern->accel_csr[accel_id].address + addr + step - OFFSET_KERNEL_CRA;
508-
val += step;
509-
size -= step;
510-
step = 0;
511-
} else {
512-
step += (unsigned)sizeof(int);
529+
#ifdef __linux__
530+
acl_sig_block_signals();
531+
#endif
532+
{
533+
std::lock_guard<std::mutex> lock(kern->segment_mutex);
534+
uintptr_t segment_offset = acl_kernel_cra_set_segment(kern, accel_id, addr);
535+
uintptr_t logical_addr =
536+
kern->accel_csr[accel_id].address + addr - OFFSET_KERNEL_CRA;
537+
uintptr_t segment = logical_addr & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
538+
539+
uintptr_t logical_addr_end =
540+
kern->accel_csr[accel_id].address + addr + size - OFFSET_KERNEL_CRA;
541+
uintptr_t segment_end =
542+
logical_addr_end & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
543+
544+
unsigned int step = 0;
545+
if (segment != segment_end) {
546+
ACL_KERNEL_IF_DEBUG_MSG_VERBOSE(
547+
kern, 2, ":: Segment change during block write detected.\n");
548+
while (step < size) {
549+
segment =
550+
(logical_addr + step) & ((size_t)0 - (KERNEL_CRA_SEGMENT_SIZE));
551+
if (kern->cur_segment != segment) {
552+
acl_kernel_if_write_block(
553+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val,
554+
step);
555+
segment_offset =
556+
acl_kernel_cra_set_segment(kern, accel_id, addr + step);
557+
logical_addr = kern->accel_csr[accel_id].address + addr + step -
558+
OFFSET_KERNEL_CRA;
559+
val += step;
560+
size -= step;
561+
step = 0;
562+
} else {
563+
step += (unsigned)sizeof(int);
564+
}
513565
}
514566
}
567+
result = acl_kernel_if_write_block(
568+
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val,
569+
size);
515570
}
516-
517-
return acl_kernel_if_write_block(
518-
kern, (unsigned)OFFSET_KERNEL_CRA + (unsigned)segment_offset, val, size);
571+
#ifdef __linux__
572+
acl_sig_unblock_signals();
573+
#endif
574+
return result;
519575
}
520576

521577
// Private utility function to issue a command to the profile hardware
@@ -1470,16 +1526,6 @@ void acl_kernel_if_update_status(acl_kernel_if *kern) {
14701526
ACL_KERNEL_IF_DEBUG_MSG_VERBOSE(kern, 5, ":: Updating kernel status.\n");
14711527
#endif
14721528

1473-
// Get the state of kernel_cra address span extender segment prior to IRQ in
1474-
// hardware If IRQ is received in middle of segment change, segment value in
1475-
// cache and hardware could go out of sync
1476-
unsigned int segment;
1477-
acl_kernel_if_read_32b(kern, OFFSET_KERNEL_CRA_SEGMENT, &segment);
1478-
1479-
// Zero upper 32-bits on 64-bit machines
1480-
kern->cur_segment = segment & 0xffffffff;
1481-
uintptr_t segment_pre_irq = kern->cur_segment;
1482-
14831529
// Check which accelerators are done and update their status appropriately
14841530
for (unsigned int accel_id = 0; accel_id < kern->num_accel; ++accel_id) {
14851531
int next_queue_back;
@@ -1552,14 +1598,6 @@ void acl_kernel_if_update_status(acl_kernel_if *kern) {
15521598
}
15531599
}
15541600
}
1555-
1556-
// Restore value of kernel cra address span extender segment to that of prior
1557-
// to IRQ
1558-
if (kern->cur_segment != segment_pre_irq) {
1559-
acl_kernel_if_write_32b(kern, OFFSET_KERNEL_CRA_SEGMENT,
1560-
(unsigned int)segment_pre_irq);
1561-
kern->cur_segment = segment_pre_irq;
1562-
}
15631601
}
15641602

15651603
void acl_kernel_if_debug_dump_printf(acl_kernel_if *kern, unsigned k) {

0 commit comments

Comments
 (0)