|  | /* | 
|  | Copyright (c) 2014-2015 Intel Corporation.  All Rights Reserved. | 
|  |  | 
|  | Redistribution and use in source and binary forms, with or without | 
|  | modification, are permitted provided that the following conditions | 
|  | are met: | 
|  |  | 
|  | * Redistributions of source code must retain the above copyright | 
|  | notice, this list of conditions and the following disclaimer. | 
|  | * Redistributions in binary form must reproduce the above copyright | 
|  | notice, this list of conditions and the following disclaimer in the | 
|  | documentation and/or other materials provided with the distribution. | 
|  | * Neither the name of Intel Corporation nor the names of its | 
|  | contributors may be used to endorse or promote products derived | 
|  | from this software without specific prior written permission. | 
|  |  | 
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "coi_device.h" | 
|  |  | 
|  | #include "coi_version_asm.h" | 
|  |  | 
|  | #define CYCLE_FREQUENCY     1000000000 | 
|  |  | 
|  |  | 
|  | static uint32_t engine_index; | 
|  | static char *engine_dir; | 
|  |  | 
|  |  | 
|  | extern "C" | 
|  | { | 
|  |  | 
|  | COIRESULT | 
|  | SYMBOL_VERSION (COIBufferAddRef, 1) (void *ptr) | 
|  | { | 
|  | COITRACE ("COIBufferAddRef"); | 
|  |  | 
|  | /* Looks like we have nothing to do here.  */ | 
|  |  | 
|  | return COI_SUCCESS; | 
|  | } | 
|  |  | 
|  |  | 
|  | COIRESULT | 
|  | SYMBOL_VERSION (COIBufferReleaseRef, 1) (void *ptr) | 
|  | { | 
|  | COITRACE ("COIBufferReleaseRef"); | 
|  |  | 
|  | /* Looks like we have nothing to do here.  */ | 
|  |  | 
|  | return COI_SUCCESS; | 
|  | } | 
|  |  | 
|  |  | 
|  | COIRESULT | 
|  | SYMBOL_VERSION (COIEngineGetIndex, 1) (COI_ISA_TYPE *type, | 
|  | uint32_t *index) | 
|  | { | 
|  | COITRACE ("COIEngineGetIndex"); | 
|  |  | 
|  | /* type is not used in liboffloadmic.  */ | 
|  | *index = engine_index; | 
|  |  | 
|  | return COI_SUCCESS; | 
|  | } | 
|  |  | 
|  |  | 
|  | COIRESULT | 
|  | SYMBOL_VERSION (COIPipelineStartExecutingRunFunctions, 1) () | 
|  | { | 
|  | COITRACE ("COIPipelineStartExecutingRunFunctions"); | 
|  |  | 
|  | /* Looks like we have nothing to do here.  */ | 
|  |  | 
|  | return COI_SUCCESS; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* The start routine for the COI pipeline thread.  */ | 
|  |  | 
|  | static void * | 
|  | pipeline_thread_routine (void *in_pipeline_num) | 
|  | { | 
|  | uint32_t pipeline_num = *(uint32_t *) in_pipeline_num; | 
|  | free (in_pipeline_num); | 
|  |  | 
|  | /* Open pipes.  */ | 
|  | char *pipe_host2tgt_path, *pipe_tgt2host_path; | 
|  | MALLOCN (char *, pipe_host2tgt_path, | 
|  | strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "0000000000")); | 
|  | MALLOCN (char *, pipe_tgt2host_path, | 
|  | strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "0000000000")); | 
|  | sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "%010d", engine_dir, | 
|  | pipeline_num); | 
|  | sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "%010d", engine_dir, | 
|  | pipeline_num); | 
|  | int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY); | 
|  | if (pipe_host2tgt < 0) | 
|  | COIERRORN ("Cannot open host-to-target pipe."); | 
|  | int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY); | 
|  | if (pipe_tgt2host < 0) | 
|  | COIERRORN ("Cannot open target-to-host pipe."); | 
|  |  | 
|  | free (pipe_host2tgt_path); | 
|  | free (pipe_tgt2host_path); | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | /* Read and execute command.  */ | 
|  | cmd_t cmd = CMD_PIPELINE_DESTROY; | 
|  | int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t)); | 
|  | if (cmd_len != sizeof (cmd_t) && cmd_len != 0) | 
|  | COIERRORN ("Cannot read from pipe."); | 
|  |  | 
|  | if (cmd == CMD_PIPELINE_DESTROY) | 
|  | break; | 
|  | else if (cmd == CMD_PIPELINE_RUN_FUNCTION) | 
|  | { | 
|  | /* Receive data from host.  */ | 
|  | void (*func) (uint32_t, void **, uint64_t *, void *, uint16_t, void *, | 
|  | uint16_t); | 
|  | uint32_t buffer_count; | 
|  | READN (pipe_host2tgt, &func, sizeof (void *)); | 
|  | READN (pipe_host2tgt, &buffer_count, sizeof (uint32_t)); | 
|  | void **buffers; | 
|  | uint64_t *buffers_len; | 
|  | MALLOCN (void **, buffers, buffer_count * sizeof (void *)); | 
|  | MALLOCN (uint64_t *, buffers_len, buffer_count * sizeof (uint64_t)); | 
|  | for (uint32_t i = 0; i < buffer_count; i++) | 
|  | { | 
|  | READN (pipe_host2tgt, &buffers_len[i], sizeof (uint64_t)); | 
|  | READN (pipe_host2tgt, &buffers[i], sizeof (void *)); | 
|  | } | 
|  | uint16_t misc_data_len; | 
|  | READN (pipe_host2tgt, &misc_data_len, sizeof (uint16_t)); | 
|  | void *misc_data = NULL; | 
|  | if (misc_data_len > 0) | 
|  | { | 
|  | MALLOCN (void *, misc_data, misc_data_len); | 
|  | READN (pipe_host2tgt, misc_data, misc_data_len); | 
|  | } | 
|  | uint16_t return_data_len; | 
|  | READN (pipe_host2tgt, &return_data_len, sizeof (uint16_t)); | 
|  | void *return_data; | 
|  | if (return_data_len > 0) | 
|  | MALLOCN (void *, return_data, return_data_len); | 
|  |  | 
|  | /* Run function.  */ | 
|  | func (buffer_count, buffers, buffers_len, misc_data, | 
|  | misc_data_len, return_data, return_data_len); | 
|  |  | 
|  | /* Send data to host if any or just send notification.  */ | 
|  | WRITEN (pipe_tgt2host, return_data_len > 0 ? return_data : &cmd, | 
|  | return_data_len > 0 ? return_data_len : sizeof (cmd_t)); | 
|  |  | 
|  | /* Clean up.  */ | 
|  | free (buffers); | 
|  | free (buffers_len); | 
|  | if (misc_data_len > 0) | 
|  | free (misc_data); | 
|  | if (return_data_len > 0) | 
|  | free (return_data); | 
|  | } | 
|  | else | 
|  | COIERRORN ("Unrecognizable command from host."); | 
|  | } | 
|  |  | 
|  | /* Close pipes.  */ | 
|  | if (close (pipe_host2tgt) < 0) | 
|  | COIERRORN ("Cannot close host-to-target pipe."); | 
|  | if (close (pipe_tgt2host) < 0) | 
|  | COIERRORN ("Cannot close target-to-host pipe."); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | COIRESULT | 
|  | SYMBOL_VERSION (COIProcessWaitForShutdown, 1) () | 
|  | { | 
|  | COITRACE ("COIProcessWaitForShutdown"); | 
|  |  | 
|  | engine_dir = getenv (MIC_DIR_ENV); | 
|  | char *mic_index = getenv (MIC_INDEX_ENV); | 
|  | assert (engine_dir != NULL && mic_index != NULL); | 
|  |  | 
|  | /* Get engine index.  */ | 
|  | engine_index = atoi (mic_index); | 
|  |  | 
|  | /* Open main pipes.  */ | 
|  | char *pipe_host2tgt_path, *pipe_tgt2host_path; | 
|  | MALLOC (char *, pipe_host2tgt_path, | 
|  | strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "mainpipe")); | 
|  | MALLOC (char *, pipe_tgt2host_path, | 
|  | strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "mainpipe")); | 
|  | sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "mainpipe", engine_dir); | 
|  | sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "mainpipe", engine_dir); | 
|  | int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY); | 
|  | if (pipe_host2tgt < 0) | 
|  | COIERROR ("Cannot open host-to-target main pipe."); | 
|  | int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY); | 
|  | if (pipe_tgt2host < 0) | 
|  | COIERROR ("Cannot open target-to-host main pipe."); | 
|  |  | 
|  | /* Clean up.  */ | 
|  | free (pipe_host2tgt_path); | 
|  | free (pipe_tgt2host_path); | 
|  |  | 
|  | /* Handler.  */ | 
|  | while (1) | 
|  | { | 
|  | /* Read and execute command.  */ | 
|  | cmd_t cmd = CMD_SHUTDOWN; | 
|  | int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t)); | 
|  | if (cmd_len != sizeof (cmd_t) && cmd_len != 0) | 
|  | COIERROR ("Cannot read from main pipe."); | 
|  |  | 
|  | switch (cmd) | 
|  | { | 
|  | case CMD_BUFFER_COPY: | 
|  | { | 
|  | uint64_t len; | 
|  | void *dest, *source; | 
|  |  | 
|  | /* Receive data from host.  */ | 
|  | READ (pipe_host2tgt, &dest, sizeof (void *)); | 
|  | READ (pipe_host2tgt, &source, sizeof (void *)); | 
|  | READ (pipe_host2tgt, &len, sizeof (uint64_t)); | 
|  |  | 
|  | /* Copy.  */ | 
|  | memcpy (dest, source, len); | 
|  |  | 
|  | /* Notify host about completion.  */ | 
|  | WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t)); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_BUFFER_MAP: | 
|  | { | 
|  | char *name; | 
|  | size_t len; | 
|  | uint64_t buffer_len; | 
|  | void *buffer; | 
|  |  | 
|  | /* Receive data from host.  */ | 
|  | READ (pipe_host2tgt, &len, sizeof (size_t)); | 
|  | MALLOC (char *, name, len); | 
|  | READ (pipe_host2tgt, name, len); | 
|  | READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t)); | 
|  |  | 
|  | /* Open shared memory.  */ | 
|  | int fd = shm_open (name, O_CLOEXEC | O_RDWR, S_IRUSR | S_IWUSR); | 
|  | if (fd < 0) | 
|  | COIERROR ("Cannot open shared memory."); | 
|  |  | 
|  | /* Map shared memory.  */ | 
|  | buffer = mmap (NULL, buffer_len, PROT_READ | PROT_WRITE, | 
|  | MAP_SHARED, fd, 0); | 
|  | if (buffer == NULL) | 
|  | COIERROR ("Cannot map shared memory."); | 
|  |  | 
|  | /* Send data to host.  */ | 
|  | WRITE (pipe_tgt2host, &fd, sizeof (int)); | 
|  | WRITE (pipe_tgt2host, &buffer, sizeof (void *)); | 
|  |  | 
|  | /* Clean up.  */ | 
|  | free (name); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_BUFFER_UNMAP: | 
|  | { | 
|  | int fd; | 
|  | uint64_t buffer_len; | 
|  | void *buffer; | 
|  |  | 
|  | /* Receive data from host.  */ | 
|  | READ (pipe_host2tgt, &fd, sizeof (int)); | 
|  | READ (pipe_host2tgt, &buffer, sizeof (void *)); | 
|  | READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t)); | 
|  |  | 
|  | /* Unmap buffer.  */ | 
|  | if (munmap (buffer, buffer_len) < 0) | 
|  | COIERROR ("Cannot unmap shared memory."); | 
|  |  | 
|  | /* Close shared memory.  */ | 
|  | if (close (fd) < 0) | 
|  | COIERROR ("Cannot close shared memory file."); | 
|  |  | 
|  | /* Notify host about completion.  */ | 
|  | WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t)); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_GET_FUNCTION_HANDLE: | 
|  | { | 
|  | char *name; | 
|  | size_t len; | 
|  |  | 
|  | /* Receive data from host.  */ | 
|  | READ (pipe_host2tgt, &len, sizeof (size_t)); | 
|  | MALLOC (char *, name, len); | 
|  | READ (pipe_host2tgt, name, len); | 
|  |  | 
|  | /* Find function.  */ | 
|  | void *ptr = dlsym (RTLD_DEFAULT, name); | 
|  | if (ptr == NULL) | 
|  | COIERROR ("Cannot find symbol %s.", name); | 
|  |  | 
|  | /* Send data to host.  */ | 
|  | WRITE (pipe_tgt2host, &ptr, sizeof (void *)); | 
|  |  | 
|  | /* Clean up.  */ | 
|  | free (name); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_OPEN_LIBRARY: | 
|  | { | 
|  | char *lib_path; | 
|  | size_t len; | 
|  |  | 
|  | /* Receive data from host.  */ | 
|  | READ (pipe_host2tgt, &len, sizeof (size_t)); | 
|  | MALLOC (char *, lib_path, len); | 
|  | READ (pipe_host2tgt, lib_path, len); | 
|  |  | 
|  | /* Open library.  */ | 
|  | void *handle = dlopen (lib_path, RTLD_LAZY | RTLD_GLOBAL); | 
|  | if (handle == NULL) | 
|  | COIERROR ("Cannot load %s: %s", lib_path, dlerror ()); | 
|  |  | 
|  | /* Send data to host.  */ | 
|  | WRITE (pipe_tgt2host, &handle, sizeof (void *)); | 
|  |  | 
|  | /* Clean up.  */ | 
|  | free (lib_path); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_CLOSE_LIBRARY: | 
|  | { | 
|  | /* Receive data from host.  */ | 
|  | void *handle; | 
|  | READ (pipe_host2tgt, &handle, sizeof (void *)); | 
|  |  | 
|  | dlclose (handle); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case CMD_PIPELINE_CREATE: | 
|  | { | 
|  | /* Receive data from host.  */ | 
|  | uint32_t *pipeline_num; | 
|  | MALLOC (uint32_t *, pipeline_num, sizeof (uint32_t)); | 
|  | READ (pipe_host2tgt, pipeline_num, sizeof (*pipeline_num)); | 
|  |  | 
|  | /* Create a new thread for the pipeline.  */ | 
|  | pthread_t thread; | 
|  | if (pthread_create (&thread, NULL, pipeline_thread_routine, | 
|  | pipeline_num)) | 
|  | COIERROR ("Cannot create new thread."); | 
|  | break; | 
|  | } | 
|  | case CMD_SHUTDOWN: | 
|  | if (close (pipe_host2tgt) < 0) | 
|  | COIERROR ("Cannot close host-to-target main pipe."); | 
|  | if (close (pipe_tgt2host) < 0) | 
|  | COIERROR ("Cannot close target-to-host main pipe."); | 
|  | return COI_SUCCESS; | 
|  | default: | 
|  | COIERROR ("Unrecognizable command from host."); | 
|  | } | 
|  | } | 
|  |  | 
|  | return COI_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | uint64_t | 
|  | SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) () | 
|  | { | 
|  | COITRACE ("COIPerfGetCycleFrequency"); | 
|  |  | 
|  | return (uint64_t) CYCLE_FREQUENCY; | 
|  | } | 
|  |  | 
|  | } // extern "C" | 
|  |  |