3.2.2.6. MCRC64

Introduction

The MCRC64 driver provides access to the hardware MCRC64 engine available on J722S devices. This driver is available as kernel module in the current SDK release.

It supports crc64 hardware acceleration.

Building MCRC64 driver

For devices with available MCRC64 engine, a Linux driver and additionally a kernel module, user-space interface for hash algorithms is used to access them. Other devices use the pure software implementation of these crc64 calculations.

J722S SoCs support a hardware accelerator called MCRC64 engine for crc64 calculations.

The kernel configuration has already been set up in the SDK and no further configuration is needed for the driver to be built as kernel module.

For reference, the configuration details are shown below. The configuration of the MCRC64 driver is done under the Hardware crypto devices sub-menu of the Cryptographic API menu in the kernel configuration.

Symbol: CRYPTO_DEV_TI_MCRC64 [=m]
Type  : tristate
Defined at drivers/crypto/ti/Kconfig:2
  Prompt: Texas Instruments MCRC64 engine support
  Depends on: CRYPTO [=y] && CRYPTO_HW [=y] && (ARCH_K3 [=y] || COMPILE_TEST [=n])
  Location:
    -> Cryptographic API (CRYPTO [=y])
      -> Hardware crypto devices (CRYPTO_HW [=y])
(1)     -> Texas Instruments MCRC64 engine support (CRYPTO_DEV_TI_MCRC64 [=m])
Selects: CRYPTO_HASH [=y] && CRYPTO_CRC64_ISO3309 [=m]

To check if mcrc64 module is properly installed, run the below command from the Linux command prompt:

root@<machine># lsmod | grep mcrc64
mcrc64  20480  0

Build the algif_hash kernel module using SDK

For using user application to access the MCRC64 Drivers above, the algif_hash kernel module is required (can be built as module). It is built as part of the SDK and no further configuration is needed.

algif_hash: User-space interface for hash algorithms

For reference, the configuration details are shown below.

Symbol: CRYPTO_USER_API_HASH [=m]
 Type  : tristate
 Defined at crypto/Kconfig:1869
   Prompt: User-space interface for hash algorithms
   Depends on: CRYPTO [=y] && NET [=y]
   Location:
     -> Cryptographic API (CRYPTO [=y])
 Selects: CRYPTO_HASH [=y] && CRYPTO_USER_API [=m]

The following shows the command used to query the system for the state of the algif_hash module.

Note

If not already loaded, these modules will get loaded automatically while running user space application.

root@<machine># lsmod | grep alg
algif_hash             20480  0
af_alg                 32768  1 algif_hash

Working of MCRC64 controller

MCRC64 Controller is a module which is used to perform CRC (Cyclic Redundancy Check) to verify the integrity of memory system. A signature (CRC) representing the contents of the memory is obtained when the contents of the memory are read into MCRC64 Controller.

Writing the data into 64-bit Signature Register calculates the Signature (CRC). The 64-bit Signature Register is based on the primitive polynomial to produce the maximum length LFSR (Linear Feedback Shift Register).

The polynomial used was published in ISO-3309:1991.

Below is the mathematical representation of used primitive polynomial.

f[x] = x^(64) + x^(4) + x^(3) + x + 1

Using MCRC64 engine from user space application

In order to use MCRC64 driver from user space, AF_ALG is used. AF_ALG is User-space interface for Crypto API. Each algorithm type will provide its own implementation that plugs into af_alg. They’re keyed using a string such as “skcipher” or “hash”. The filesystem which comes with the SDK comes built with the af_alg, algif_hash kernel modules and the TI driver which directly accesses the MCRC64 engine is built as kernel module.

The following code is for user-space application to access mcrc64 engine

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <string.h>

#define BUFFER_SIZE 4096
#define SECTOR 4096

int main (int argc, char **argv) {

    int desc[2] = { -1, -1 };

    struct sockaddr_alg sock = {
        .salg_family = AF_ALG,
        .salg_type   = "hash",
        .salg_name   = "crc64-iso3309"
    };

    if ((desc[0] = socket(AF_ALG, SOCK_SEQPACKET, 0)) == -1 ) {
        perror("socket");
        return -1;
    }

    if( bind(desc[0], (struct sockaddr *) &sock, sizeof(sock)) != 0 ) {
        perror("bind");
        return -1;
    }

    if( (desc[1] = accept(desc[0], NULL, 0)) == -1 )
        return -1;

    if (argc != 2 || strlen(argv[1]) == 0) {
        printf("Please specify filename\n");
        return -1; // empty string
    }

    FILE* file;
    unsigned char *buffer;
    if(posix_memalign((void *)&buffer, SECTOR, BUFFER_SIZE)) {
        perror("posix_memalign failed");
        return -1;
    }

    file = fopen(argv[1], "rb");
    if(file == NULL)
    {
        printf("An error occured while opening file: %s\n", argv[1]);
        free(buffer);
        return -1;
    }

    while(!feof(file))
    {
        unsigned int count = fread(buffer, sizeof(char), BUFFER_SIZE, file);
        if(ferror(file))
        {
            printf("An error occurred while accessing the file: %s\n", argv[1]);
            fclose(file);
            free(buffer);
            return -1;
        }

        if (send(desc[1], buffer, count, MSG_MORE) != count) {
            free(buffer);
            return -1;
        }
    }

    long int crc64 = 0x0000000000000000;
    if(read(desc[1], &crc64, 8) != 8) {
        free(buffer);
        return -1;
    }

    printf("0x%llx\n", crc64);
    free(buffer);
    return 0;
}

Compile the code on target using below command

root@<machine># cc <filename> -o calculate_crc

Run the executable

root@<machine># ./calculate_crc <path-to-file-for-crc-calculation>

#Example
root@<machine># ./calculate_crc cscope.files
0xfa68a95edc9f3b45

Using the Linux time function gives more information about CPU usage during the test.

root@<machine># time ./calculate_crc cscope.files
0xfa68a95edc9f3b45

real    0m0.213s
user    0m0.000s
sys     0m0.213s

To verify the result against pycrc module available here on host PC.

host# time python3 ~/pycrc/src/pycrc.py --width 64 --poly 0x000000000000001b --reflect-in False --xor-in 0x0000000000000000 --reflect-out False --xor-out 0x0000000000000000 --check-file cscope.files
0xfa68a95edc9f3b45

real    1m36.405s
user    1m36.216s
sys     0m0.052s

MCRC64 engine speed testing

Testing using the tcrypt module on target:

root@<machine># sudo modprobe tcrypt mode=329 sec=1
sudo modprobe tcrypt mode=329 sec=1
[  420.706237] tcrypt: testing speed of async crc64-iso3309 (mcrc64)
[  420.712461] tcrypt: test  0 (   16 byte blocks,   16 bytes per update,   1 updates): 789148 opers/sec,  12626368 bytes/sec
[  421.719575] tcrypt: test  1 (   64 byte blocks,   16 bytes per update,   4 updates): 363004 opers/sec,  23232256 bytes/sec
[  422.727566] tcrypt: test  2 (   64 byte blocks,   64 bytes per update,   1 updates): 771433 opers/sec,  49371712 bytes/sec
[  423.735553] tcrypt: test  3 (  256 byte blocks,   16 bytes per update,  16 updates): 119069 opers/sec,  30481664 bytes/sec
[  424.743550] tcrypt: test  4 (  256 byte blocks,   64 bytes per update,   4 updates): 346712 opers/sec,  88758272 bytes/sec
[  425.751540] tcrypt: test  5 (  256 byte blocks,  256 bytes per update,   1 updates): 672290 opers/sec, 172106240 bytes/sec
[  426.759536] tcrypt: test  6 ( 1024 byte blocks,   16 bytes per update,  64 updates):  32296 opers/sec,  33071104 bytes/sec
[  427.767535] tcrypt: test  7 ( 1024 byte blocks,  256 bytes per update,   4 updates): 273303 opers/sec, 279862272 bytes/sec
[  428.775529] tcrypt: test  8 ( 1024 byte blocks, 1024 bytes per update,   1 updates): 442304 opers/sec, 452919296 bytes/sec
[  429.783523] tcrypt: test  9 ( 2048 byte blocks,   16 bytes per update, 128 updates):  16378 opers/sec,  33542144 bytes/sec
[  430.791574] tcrypt: test 10 ( 2048 byte blocks,  256 bytes per update,   8 updates): 155153 opers/sec, 317753344 bytes/sec
[  431.788486] tcrypt: test 11 ( 2048 byte blocks, 1024 bytes per update,   2 updates): 263325 opers/sec, 539289600 bytes/sec
[  432.799504] tcrypt: test 12 ( 2048 byte blocks, 2048 bytes per update,   1 updates): 303687 opers/sec, 621950976 bytes/sec
[  433.807495] tcrypt: test 13 ( 4096 byte blocks,   16 bytes per update, 256 updates):   8249 opers/sec,  33787904 bytes/sec
[  434.815592] tcrypt: test 14 ( 4096 byte blocks,  256 bytes per update,  16 updates):  83206 opers/sec, 340811776 bytes/sec
[  435.823491] tcrypt: test 15 ( 4096 byte blocks, 1024 bytes per update,   4 updates): 148290 opers/sec, 607395840 bytes/sec
[  436.831482] tcrypt: test 16 ( 4096 byte blocks, 4096 bytes per update,   1 updates): 187059 opers/sec, 766193664 bytes/sec
[  437.839475] tcrypt: test 17 ( 8192 byte blocks,   16 bytes per update, 512 updates):   4139 opers/sec,  33906688 bytes/sec
[  438.847507] tcrypt: test 18 ( 8192 byte blocks,  256 bytes per update,  32 updates):  43169 opers/sec, 353640448 bytes/sec
[  439.855468] tcrypt: test 19 ( 8192 byte blocks, 1024 bytes per update,   8 updates):  79294 opers/sec, 649576448 bytes/sec
[  440.863457] tcrypt: test 20 ( 8192 byte blocks, 4096 bytes per update,   2 updates): 100024 opers/sec, 819396608 bytes/sec
[  441.871452] tcrypt: test 21 ( 8192 byte blocks, 8192 bytes per update,   1 updates): 100349 opers/sec, 822059008 bytes/sec
modprobe: ERROR: could not insert 'tcrypt': Resource temporarily unavailable
...