Exemplo n.º 1
0
static struct unipro_xfer_descriptor *pick_tx_descriptor(void)
{
    struct unipro_xfer_descriptor *desc;
    int i;

    for (i = 0; i < unipro_cport_count(); i++) {
        struct cport *cport = cport_handle(i);
        if (!cport)
            continue;

        if (list_is_empty(&cport->tx_fifo))
            continue;

        desc = containerof(cport->tx_fifo.next, struct unipro_xfer_descriptor,
                           list);
        if (desc->channel)
            continue;

        if (!unipro_get_tx_free_buffer_space(desc->cport))
            continue;

        return desc;
    }

    return NULL;
}
Exemplo n.º 2
0
/**
 * @brief           Send data down to a CPort
 * @return          number of bytes effectively sent (>= 0), or error code (< 0)
 * @param[in]       cportid: cport to send down
 * @param[in]       buf: data buffer
 * @param[in]       len: size of data to send
 * @param[in]       som: "start of message" flag
 */
static int unipro_send_sync(unsigned int cportid,
                            const void *buf, size_t len, bool som)
{
    struct cport *cport;
    uint16_t count;
    uint8_t *tx_buf;

    if (len > CPORT_BUF_SIZE) {
        return -EINVAL;
    }

    cport = cport_handle(cportid);
    if (!cport) {
        return -EINVAL;
    }

    if (!cport->connected) {
        lldbg("CP%d unconnected\n", cport->cportid);
        return -EPIPE;
    }

    DEBUGASSERT(TRANSFER_MODE == 2);

    /*
     * If this is not the start of a new message,
     * message data must be written to first address of CPort Tx Buffer + 1.
     */
    if (!som) {
        tx_buf = cport->tx_buf + sizeof(uint32_t);
    } else {
        tx_buf = cport->tx_buf;
    }

    count = unipro_get_tx_free_buffer_space(cport);
    if (!count) {
        /* No free space in TX FIFO, cannot send anything. */
        DBG_UNIPRO("No free space in CP%d Tx Buffer\n", cportid);
        return 0;
    } else if (count > len) {
        count = len;
    }
    /* Copy message data in CPort Tx FIFO */
    DBG_UNIPRO("Sending %u bytes to CP%d\n", count, cportid);
    memcpy(tx_buf, buf, count);

    return (int) count;
}
Exemplo n.º 3
0
static int unipro_continue_xfer(struct unipro_xfer_descriptor *desc)
{
    size_t xfer_len;

    desc->remaining_xfer_len -= desc->dma_arg.unipro_tx_arg.next_transfer_len;

    xfer_len = unipro_get_tx_free_buffer_space(desc->cport);
    if (!xfer_len)
        return -ENOSPC;

    xfer_len = MIN(desc->remaining_xfer_len, xfer_len);
    desc->dma_arg.unipro_tx_arg.next_transfer_len = xfer_len;

    if (xfer_len == desc->remaining_xfer_len)
        desc->dma_arg.unipro_tx_arg.eom_addr = CPORT_EOM_BIT(desc->cport);

    return 0;
}
Exemplo n.º 4
0
static int unipro_dma_xfer(struct unipro_xfer_descriptor *desc,
                           struct dma_channel *channel)
{
    int retval;
    size_t xfer_len;
    void *cport_buf;
    void *xfer_buf;

    xfer_len = unipro_get_tx_free_buffer_space(desc->cport);
    if (!xfer_len)
        return -ENOSPC;

    xfer_len = MIN(desc->remaining_xfer_len, xfer_len);

    desc->channel = channel;
    desc->dma_arg.unipro_tx_arg.next_transfer_len = xfer_len;
    if (xfer_len == desc->remaining_xfer_len)
        desc->dma_arg.unipro_tx_arg.eom_addr = CPORT_EOM_BIT(desc->cport);

    DBG_UNIPRO("xfer: chan=%u, len=%zu\n", channel->id, xfer_len);

    cport_buf = desc->cport->tx_buf;
    xfer_buf = (void*) desc->data;

    /* resuming a paused xfer */
    if (desc->remaining_xfer_len != desc->len) {
        cport_buf = (char*) cport_buf + 1; /* skip the start byte */

        /* move buffer offset to the beginning of the remaning bytes to xfer */
        xfer_buf = (char*) xfer_buf + (desc->len - desc->remaining_xfer_len);
    }

    retval = device_dma_transfer(unipro_dma.dev, channel->id, xfer_buf,
                                 cport_buf, xfer_len, &desc->dma_arg);
    if (retval) {
        lowsyslog("unipro: failed to start DMA transfer: %d\n", retval);
        return retval;
    }

    return 0;
}
Exemplo n.º 5
0
static struct unipro_xfer_descriptor *pick_tx_descriptor(unsigned int cportid)
{
    struct unipro_xfer_descriptor *desc;
    unsigned int cport_count = unipro_cport_count();
    int i;

    for (i = 0; i < cport_count; i++, cportid++) {
        struct cport *cport;

        cportid = cportid % cport_count;
        cport = cport_handle(cportid);
        if (!cport)
            continue;

        if (list_is_empty(&cport->tx_fifo)) {
            if (cport->pending_reset) {
                unipro_flush_cport(cport);
            }

            continue;
        }

        if (cport->pending_reset) {
            unipro_flush_cport(cport);
        }

        desc = containerof(cport->tx_fifo.next, struct unipro_xfer_descriptor,
                list);
        if (desc->channel)
            continue;

        if (!unipro_get_tx_free_buffer_space(desc->cport))
            continue;

        return desc;
    }

    return NULL;
}
Exemplo n.º 6
0
static int unipro_dma_xfer(struct unipro_xfer_descriptor *desc,
                           struct dma_channel *channel)
{
    int retval;
    size_t xfer_len;
    void *cport_buf;
    void *xfer_buf;
    struct device_dma_op *dma_op = NULL;

    if (tsb_get_rev_id() == tsb_rev_es2) {
        xfer_len = unipro_get_tx_free_buffer_space(desc->cport);
        if (!xfer_len)
            return -ENOSPC;

        xfer_len = MIN(desc->len - desc->data_offset, xfer_len);
    } else {
        DEBUGASSERT(desc->data_offset == 0);

        xfer_len = desc->len;
    }

    desc->channel = channel;
    retval = device_dma_op_alloc(unipro_dma.dev, 1, 0, &dma_op);
    if (retval != OK) {
        lowsyslog("unipro: failed allocate a DMA op, retval = %d.\n", retval);
        return retval;
    }

    dma_op->callback = (void *) unipro_dma_tx_callback;
    dma_op->callback_arg = desc;
    dma_op->callback_events = DEVICE_DMA_CALLBACK_EVENT_COMPLETE;
    if (tsb_get_rev_id() != tsb_rev_es2) {
       dma_op->callback_events |=  DEVICE_DMA_CALLBACK_EVENT_START;
    }
    dma_op->sg_count = 1;
    dma_op->sg[0].len = xfer_len;

    DBG_UNIPRO("xfer: chan=%u, len=%zu\n", channel->id, xfer_len);

    cport_buf = desc->cport->tx_buf;
    xfer_buf = (void*) desc->data;

    /* resuming a paused xfer */
    if (desc->data_offset != 0) {
        cport_buf = (char*) cport_buf + sizeof(uint64_t); /* skip the first DWORD */

        /* move buffer offset to the beginning of the remaning bytes to xfer */
        xfer_buf = (char*) xfer_buf + desc->data_offset;
    }

    dma_op->sg[0].src_addr = (off_t) xfer_buf;
    dma_op->sg[0].dst_addr = (off_t) cport_buf;

    desc->data_offset += xfer_len;

    retval = device_dma_enqueue(unipro_dma.dev, channel->chan, dma_op);
    if (retval) {
        lowsyslog("unipro: failed to start DMA transfer: %d\n", retval);
        return retval;
    }

    return 0;
}