OpenCores
URL https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk

Subversion Repositories funbase_ip_library

[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.swp.api/] [openmcapi/] [1.0/] [libmcapi/] [shm/] [linux/] [shm_os.c] - Rev 145

Compare with Previous | Blame | View Log

/*
 * Copyright (c) 2010, Mentor Graphics 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:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of the <ORGANIZATION> 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 <mcapi.h>
#include "../shm.h"
#include "../shm_os.h"
 
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
 
typedef uint32_t mcomm_core_t;
typedef uint32_t mcomm_mbox_t;
 
/* Specify the layout of the mailboxes in shared memory */
#define MCOMM_INIT       _IOW('*', 0, struct mcomm_init_device)
/* All values in bytes */
struct mcomm_init_device {
    mcomm_mbox_t nr_mboxes;
    uint32_t offset; /* Offset from base of shared memory to first mailbox */
    uint32_t mbox_size;
    uint32_t mbox_stride; /* Offset from mailbox N to mailbox N+1 */
};
 
/* Get hardware-defined number for the current core */
#define MCOMM_CPUID      _IOR('*', 1, mcomm_core_t)
 
/* Block until data is available for specified mailbox */
#define MCOMM_WAIT_READ  _IOW('*', 2, mcomm_mbox_t)
 
/* Notify the specified core that data has been made available to it */
#define MCOMM_NOTIFY     _IOW('*', 3, mcomm_core_t)
 
 
static pthread_t shm_rx_thread;
 
/* XXX must close mcomm_fd somewhere */
static int mcomm_fd;
static size_t shm_bytes;
 
#define MCOMM_DEVICE "/dev/mcomm0"
 
static size_t shm_linux_read_size(void)
{
    unsigned long size;
    FILE *f;
    int rc;
 
    f = fopen("/sys/devices/platform/mcomm.0/size", "r");
    if (!f)
        f = fopen("/sys/devices/mcomm.0/size", "r");
    if (!f)
        return errno;
 
    rc = fscanf(f, "%lx", &size);
    if (rc < 0)
        size = errno;
 
    fclose(f);
 
    return size;
}
 
mcapi_status_t openmcapi_shm_notify(mcapi_uint32_t unit_id,
                                    mcapi_uint32_t node_id)
{
    mcapi_status_t mcapi_status = MCAPI_SUCCESS;
    int rc;
 
    rc = ioctl(mcomm_fd, MCOMM_NOTIFY, &unit_id);
    if (rc)
        mcapi_status = MCAPI_OS_ERROR;
 
    return mcapi_status;
}
 
mcapi_uint32_t openmcapi_shm_schedunitid(void)
{
    mcapi_uint32_t core_id;
    int rc;
 
    rc = ioctl(mcomm_fd, MCOMM_CPUID, &core_id);
    if (rc)
        return MCAPI_OS_ERROR;
 
    return core_id;
}
 
static int shm_linux_wait_notify(mcapi_uint32_t unitId)
{
    return ioctl(mcomm_fd, MCOMM_WAIT_READ, &unitId);
}
 
static int shm_linux_init_device(int fd)
{
    struct mcomm_init_device args;
    struct _shm_drv_mgmt_struct_ *mgmt = NULL;
 
    args.nr_mboxes = CONFIG_SHM_NR_NODES;
    args.offset = (unsigned int)&mgmt->shm_queues[0].count;
    args.mbox_size = sizeof(mgmt->shm_queues[0].count);
    args.mbox_stride = (void *)&mgmt->shm_queues[1].count -
                       (void *)&mgmt->shm_queues[0].count;
 
    return ioctl(fd, MCOMM_INIT, &args);
}
 
void *openmcapi_shm_map(void)
{
    void *shm;
    int fd;
    int rc;
 
    shm_bytes = shm_linux_read_size();
    if (shm_bytes <= 0) {
        perror("read shared memory size");
        return NULL;
    }
 
    fd = open(MCOMM_DEVICE, O_RDWR);
    if (fd < 0) {
        perror("open " MCOMM_DEVICE);
        goto out1;
    }
 
    /* Get the new file descriptor for the initialized device. */
    rc = shm_linux_init_device(fd);
    if (rc < 0) {
        perror("couldn't initialize device");
        goto out2;
    }
 
    mcomm_fd = rc;
 
    shm = mmap(NULL, shm_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, mcomm_fd, 0);
    if (shm == MAP_FAILED) {
        perror("mmap shared memory");
        goto out3;
    }
 
    /* Don't need the original fd around any more. */
    close(fd);
 
    return shm;
 
out3:
    close(mcomm_fd);
out2:
    close(fd);
out1:
    return NULL;
}
 
/* pthread cancellation is tricky.
 *
 * First, we need to ensure that if we're blocked in the kernel (ioctl),
 * pthread_cancel must send us a signal so we return to userspace to handle it.
 * This is accomplished with PTHREAD_CANCEL_ASYNCHRONOUS, without which glibc
 * would set some state and then happily wait for us to hit the next
 * cancellation point (see pthreads(7)). However, we wouldn't, because we'd
 * never wake from the kernel.
 *
 * Second, pthread_cancel() could be called any time outside the
 * PTHREAD_CANCEL_ASYNCHRONOUS section. Since we don't necessarily have any
 * cancellation points inside the loop (including the shm_poll() path), we must
 * manually check by calling pthread_testcancel().
 */
static void *mcapi_receive_thread(void *data)
{
    int rc;
    int canceltype;
 
    do {
        /* Manually check if we're already dead. */
        pthread_testcancel();
 
        /* Block until data for this node is available or we are canceled with
         * a signal. */
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &canceltype);
        rc = shm_linux_wait_notify(MCAPI_Node_ID);
        if (rc < 0) {
            perror("wait ioctl");
            break;
        }
        pthread_setcanceltype(canceltype, NULL);
 
        /* Obtain lock so we can safely manipulate the RX_Queue. */
        MCAPI_Lock_RX_Queue();
 
        /* Process the incoming data. */
        shm_poll();
 
        MCAPI_Unlock_RX_Queue(0);
 
    } while (1);
 
    printf("%s exiting!\n", __func__);
    return NULL;
}
 
/* Now that SM_Mgmt_Blk has been initialized, we can start the RX thread. */
mcapi_status_t openmcapi_shm_os_init(void)
{
    mcapi_status_t mcapi_status = MCAPI_SUCCESS;
    int rc;
 
    rc = pthread_create(&shm_rx_thread, NULL, mcapi_receive_thread, NULL);
    if (rc) {
        perror("couldn't create pthread");
        mcapi_status = MCAPI_OS_ERROR;
    }
 
    return mcapi_status;
}
 
/* Finalize the SM driver OS specific layer. */
mcapi_status_t openmcapi_shm_os_finalize(void)
{
    mcapi_status_t mcapi_status = MCAPI_SUCCESS;
    int rc;
 
    rc = pthread_cancel(shm_rx_thread);
    if (rc) {
        perror("couldn't cancel thread");
        mcapi_status = MCAPI_OS_ERROR;
    }
 
    /* Don't return until it's dead. */
    rc = pthread_join(shm_rx_thread, NULL);
    if (rc) {
        perror("couldn't joined canceled thread");
        mcapi_status = MCAPI_OS_ERROR;
    }
 
    return mcapi_status;
}
 
void openmcapi_shm_unmap(void *shm)
{
    munmap(shm, shm_bytes);
 
    close(mcomm_fd);
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.