diff --git a/sys/arm64/qoriq/caam/caam.c b/sys/arm64/qoriq/caam/caam.c --- a/sys/arm64/qoriq/caam/caam.c +++ b/sys/arm64/qoriq/caam/caam.c @@ -10,6 +10,8 @@ #include +#include "opt_caam.h" /* For the CAAM_DEBUG option */ + #include #include #include @@ -29,6 +31,7 @@ #include "caam.h" #include "caam_debug.h" #include "caam_internal.h" +#include "caam_test.h" #include "jr/caam_jobdesc.h" #include "jr/caam_jr.h" #include "jr/caam_jr_hw.h" @@ -417,8 +420,21 @@ goto cleanup_rman; } +#ifdef CAAM_DEBUG + /* Add the caam test device for development */ + rv = caam_test_attach(dev); + if (rv != 0) { + CAAM_LOG_ERROR("caam_test_attach failed rv=(%d)\n", rv); + goto cleanup_jobrings; + } +#endif + return (0); +#ifdef CAAM_DEBUG +cleanup_jobrings: + caam_jobrings_detach(dev); +#endif cleanup_rman: rman_fini(&sc->mem_rman); cleanup_resource: @@ -479,6 +495,11 @@ { struct caam_softc *sc = device_get_softc(dev); +#ifdef CAAM_DEBUG + /* Remove the caam test device */ + caam_test_detach(dev); +#endif + caam_jobrings_detach(dev); rman_fini(&sc->mem_rman); diff --git a/sys/arm64/qoriq/caam/caam_test.h b/sys/arm64/qoriq/caam/caam_test.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam_test.h @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Alstom Group + * Copyright 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_TEST_H +#define CAAM_TEST_H + +#include + +/* These functions are used to setup and free the test drivers*/ +int caam_test_attach(device_t dev); +int caam_test_detach(device_t dev); + +#endif /* CAAM_TEST_H */ \ No newline at end of file diff --git a/sys/arm64/qoriq/caam/caam_test.c b/sys/arm64/qoriq/caam/caam_test.c new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam_test.c @@ -0,0 +1,349 @@ +/* + * Copyright 2024 Alstom Group + * Copyright 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include + +#include +#include +#include /* cdevsw struct */ +#include +#include +#include +#include +#include /* uio struct */ + +#include + +#include + +#include "caam.h" +#include "caam_debug.h" +#include "caam_internal.h" +#include "caam_test.h" +#include "jr/caam_jobdesc.h" +#include "jr/caam_jr_hw.h" + +/* Reference to the CAAM device on witch to execute the tests. */ +static device_t g_caam_dev; + +/* Utility static functions */ +/* `borrowed` from sys/cam/ctl/ctl.c */ +static int +hex2bin(const char *str, uint8_t *buf, int buf_size) +{ + int i; + u_char c; + + memset(buf, 0, buf_size); + while (isspace(str[0])) + str++; + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + buf_size *= 2; + for (i = 0; str[i] != 0 && i < buf_size; i++) { + while (str[i] == '-') /* Skip dashes in UUIDs. */ + str++; + c = str[i]; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= 16) + break; + if ((i & 1) == 0) + buf[i / 2] |= (c << 4); + else + buf[i / 2] |= c; + } + return ((i + 1) / 2); +} + +static void +print_hex(const char *message, const uint8_t *buf, int buf_size) +{ + char tmp_buff[buf_size * 2 + 1]; + + for (int i = 0; i < buf_size; i++) { + tmp_buff[2 * i] = hex2ascii(buf[i] >> 4u); + tmp_buff[2 * i + 1] = hex2ascii(buf[i] & 0xFu); + } + tmp_buff[buf_size * 2] = '\0'; + + uprintf("caam_test: %s `%s`\n", message, tmp_buff); +} + +/*------------------ Functions to execute any descriptor ------------------*/ +/* Construct descriptor from provided template */ +static int +cnstr_test_jobdesc(uint32_t *desc, char *template, + const caam_jr_dma_map_t *data_map, bool little_endian) +{ + bus_addr_t phys_addr; + char *buffer, *command, *endptr; + uint32_t command_word; + + /* Current descriptor support only 64K length */ + if (data_map->buflen > 0xffffu) + return EINVAL; + + CAAM_LOG_INFO("Constructing descriptor '%s'\n", template); + caam_jobdesc_init(desc); + + buffer = template; + while ((command = strsep(&buffer, ";")) != NULL) { + if (strlen(command) != 8) { + CAAM_LOG_ERROR("Received bad command! '%s'\n", command); + return (EINVAL); + } + CAAM_LOG_INFO("Interpreting command `%s`\n", command); + + command_word = (uint32_t)strtoul(command, &endptr, 16); + if ((command_word & 0xFFFF0000) == 0xA5A50000u) { + CAAM_LOG_INFO("Received adress with offset %i\n", + command_word & 0xFFFF); + phys_addr = data_map->bus_addr + + (command_word & 0xFFFF); + + CAAM_LOG_INFO("Adding address: '%lX'\n", phys_addr); + caam_jobdesc_add_ptr(desc, phys_addr, little_endian); + } else { + CAAM_LOG_INFO("Adding word: '%08X'\n", command_word); + caam_jobdesc_add_word(desc, command_word); + } + } + + return 0; +} + +/* Execute test job descriptor + * Parameters: + * uint8_t* data_buff - user specified byte array + * uint32_t data_buff_len - number of bytes of data_buff + * Return code: + * 0 - SUCCESS + * !0 - ERROR + */ +static int +run_test_generate_job(device_t dev, char *template, uint8_t *data_buff, + uint32_t data_buff_len) +{ + int ret = 0; + struct job_descriptor desc; + struct job_descriptor *jobdesc = &desc; + caam_jr_dma_map_t data_map; + struct caam_softc *sc; + device_t jr_dev; + + sc = device_get_softc(dev); + jobdesc->arg = NULL; + jobdesc->callback = NULL; + + jr_dev = jr_pool_acquire(&sc->jr_pool); + if (jr_dev == 0) { + CAAM_LOG_ERROR("Failed to acquire JR device\n"); + return EIO; + } + + /* Map the buffer to the DMA memory */ + ret = caam_jr_dma_map(jr_dev, &data_map, data_buff, data_buff_len, 0, + BUS_DMA_NOWAIT, JR_MAP_SYNC); + if (ret != 0) { + CAAM_LOG_ERROR("DMA mapping failed\n"); + jr_pool_release(&sc->jr_pool, jr_dev); + return ret; + } + + /* create the hw_rng descriptor */ + ret = cnstr_test_jobdesc(jobdesc->desc, template, &data_map, sc->little_endian); + if (ret != 0) { + CAAM_LOG_ERROR("Descriptor construction failed\n"); + goto caam_unmap; + } + + print_hex("Descriptor:", (void *)jobdesc->desc, + caam_jobdesc_length(jobdesc->desc) * sizeof(uint32_t)); + + /* Finally, execute the descriptor */ + ret = caam_run_descriptor_jr_blocking(dev, jobdesc, jr_dev); + if (ret != 0) { + CAAM_LOG_ERROR("Error in running descriptor\n"); + goto caam_unmap; + } + +caam_unmap: + jr_pool_release(&sc->jr_pool, jr_dev); + caam_jr_dma_unmap(jr_dev, &data_map, JR_MAP_SYNC); + + return ret; +} + +/*------ CAAM test character device (caam_test_cdev) interface functions -----*/ +#define BUFFERSIZE 1024 + +/* Static buffers used to store descriptors and input data */ +static uint8_t test_in_buf[BUFFERSIZE]; + +/* Function prototypes */ +static d_open_t caam_test_cdev_open; +static d_close_t caam_test_cdev_close; +static d_write_t caam_test_cdev_write; + +/* Character device entry points */ +static struct cdevsw caam_test_cdevsw = { + .d_version = D_VERSION, + .d_open = caam_test_cdev_open, + .d_close = caam_test_cdev_close, + .d_write = caam_test_cdev_write, + .d_name = "caam_test_cdev", +}; + +/* vars */ +static struct cdev *caam_test_cdev; + +static int +caam_test_cdev_open(struct cdev *dev __unused, int oflags __unused, + int devtype __unused, struct thread *td __unused) +{ + device_t caam_dev = g_caam_dev; + + if (caam_dev == NULL) { + CAAM_LOG_ERROR("No CAAM module available!\n"); + return (ENXIO); + } + + CAAM_LOG_DEBUG("Opened CAAM TEST character device successfully.\n"); + return (0); +} + +static int +caam_test_cdev_close(struct cdev *dev __unused, int fflag __unused, + int devtype __unused, struct thread *td __unused) +{ + CAAM_LOG_DEBUG("Closing CAAM TEST character device.\n"); + return (0); +} + +/* + * The read function reads from random device and set it to userland for + * accessing. + */ +static int +caam_test_cdev_write(struct cdev *dev __unused, struct uio *uio, + int ioflag __unused) +{ + size_t amt; + int error; + uint8_t command_buffer[BUFFERSIZE]; + char *buffer, *command, *param, *value, *endptr; + + /* + * We allow write only at begining - atomic command + */ + if (uio->uio_offset != 0) + return (EINVAL); + + /* Copy the string in from user memory to kernel memory */ + amt = MIN(uio->uio_resid, sizeof(command_buffer)); + error = uiomove(command_buffer, amt, uio); + + /* Now we need to null terminate the command string */ + command_buffer[uio->uio_offset] = 0; + uprintf("caam_test: Execute: `%s`\n", command_buffer); + + buffer = command_buffer; + + command = strsep(&buffer, ":"); + uprintf("caam_test: Command: `%s`\n", command); + + if (strcmp(command, "LOAD") == 0) { + int offset = 0, length = 0; + + param = strsep(&buffer, ":"); + offset = (uint32_t)strtoul(param, &endptr, 16); + uprintf("caam_test: Param Offset: `%s` -> %i\n", param, offset); + + value = buffer; + length = strlen(value) / 2; + + uprintf("caam_test: Value: `%s`, len:%i\n", value, length); + hex2bin(value, &test_in_buf[offset], length); + } else if (strcmp(command, "READ") == 0) { + int offset, length; + + param = strsep(&buffer, ":"); + offset = (uint32_t)strtoul(param, &endptr, 16); + uprintf("caam_test: Param Offset: `%s` -> %i\n", param, offset); + + param = buffer; + length = (uint32_t)strtoul(param, &endptr, 16); + uprintf("caam_test: Param Length: `%s` -> %i\n", param, length); + + print_hex("Data:", &test_in_buf[offset], length); + } else if (strcmp(command, "EXEC") == 0) { + param = buffer; + uprintf("caam_test: Param Templates: `%s`\n", param); + + run_test_generate_job(g_caam_dev, param, test_in_buf, + sizeof(test_in_buf)); + } else { + uprintf("caam_test: Unknown command `%s`\n", command); + } + + if (error != 0) + uprintf("Write failed: bad address!\n"); + return (error); +} + +/*--------------------- CAAM device management functions --------------------*/ +int +caam_test_attach(device_t dev) +{ + int error = 0; + struct make_dev_args args; + + /* Add the character device only on the first CAAM device.*/ + if (g_caam_dev == NULL) { + g_caam_dev = dev; + + /* Register the device as read/write */ + make_dev_args_init(&args); + args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; + args.mda_devsw = &caam_test_cdevsw; + args.mda_cr = 0; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_WHEEL; + args.mda_mode = 0600; + + error = make_dev_s(&args, &caam_test_cdev, "test_caam"); + + CAAM_LOG_INFO( + "CAAM TEST /dev/test_caam character device loaded.\n"); + } + + return error; +} + +int +caam_test_detach(device_t dev) +{ + /* Remove character device only if correct CAAM + * device is detached */ + if (dev == g_caam_dev) { + CAAM_LOG_INFO( + "CAAM TEST /dev/test_caam character device removed.\n"); + destroy_dev(caam_test_cdev); + + /* at this time no clients should exist that can use the + * g_caam_dev */ + g_caam_dev = NULL; + } + + return 0; +} diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -687,6 +687,7 @@ arm64/qoriq/clk/qoriq_clk_pll.c optional clk soc_nxp_ls arm64/qoriq/clk/qoriq_clkgen.c optional clk soc_nxp_ls fdt arm64/qoriq/caam/caam.c optional caam soc_nxp_ls +arm64/qoriq/caam/caam_test.c optional caam caam_debug soc_nxp_ls arm64/qoriq/caam/jr/caam_jr.c optional caam soc_nxp_ls arm64/qoriq/caam/jr/caam_jr_pool.c optional caam soc_nxp_ls arm64/qoriq/caam/jr/caam_jobdesc.c optional caam soc_nxp_ls diff --git a/sys/conf/options b/sys/conf/options --- a/sys/conf/options +++ b/sys/conf/options @@ -1009,6 +1009,9 @@ GCOV opt_global.h LINDEBUGFS +# caam options +CAAM_DEBUG opt_caam.h + # options for HID support HID_DEBUG opt_hid.h IICHID_DEBUG opt_hid.h