Esempio 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;
}
Esempio n. 2
0
/**
 * @brief send data down a CPort
 * @param cportid cport to send down
 * @param buf data buffer
 * @param len size of data to send
 * @param 0 on success, <0 on error
 */
int unipro_send(unsigned int cportid, const void *buf, size_t len)
{
    int ret, sent;
    bool som;
    struct cport *cport;

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

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

    if (cport->pending_reset) {
        return -EPIPE;
    }

    for (som = true, sent = 0; sent < len;) {
        ret = unipro_send_sync(cportid, buf + sent, len - sent, som);
        if (ret < 0) {
            return ret;
        } else if (ret == 0) {
            continue;
        }
        sent += ret;
        som = false;
    }

    unipro_set_eom_flag(cport);

    return 0;
}
Esempio n. 3
0
/**
 * @brief           Send data buffer(s) on CPort whenever ready.
 *                  Ensure that TX queues are reinspected until
 *                  all CPorts have no work available.
 *                  Then suspend again until new data is available.
 */
static void *unipro_tx_worker(void *data)
{
    int i;
    bool is_busy;
    int retval;
    unsigned int cport_count = unipro_cport_count();

    while (1) {
        /* Block until a buffer is pending on any CPort */
        sem_wait(&worker.tx_fifo_lock);

        do {
            is_busy = false;

            for (i = 0; i < cport_count; i++) {
                /* Browse all CPorts sending any pending buffers */
                retval = unipro_send_tx_buffer(cport_handle(i));
                if (retval == -EBUSY) {
                    /*
                     * Buffer only partially sent, have to try again for
                     * remaining part.
                     */
                    is_busy = true;
                }
            }
        } while (is_busy); /* exit when CPort(s) current pending buffer sent */
    }

    return NULL;
}
Esempio n. 4
0
int unipro_driver_unregister(unsigned int cportid)
{
    struct cport *cport = cport_handle(cportid);
    if (!cport) {
        return -ENODEV;
    }

    cport->driver = NULL;

    return 0;
}
Esempio n. 5
0
/**
 * @brief Enable EOM interrupt on cport
 */
static void enable_int(unsigned int cportid) {
    struct cport *cport;
    unsigned int irqn;

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

    irqn = cportid_to_irqn(cportid);
    enable_rx_interrupt(cport);
    irq_attach(irqn, irq_rx_eom);
    up_enable_irq(irqn);
}
Esempio n. 6
0
int unipro_unpause_rx(unsigned int cportid)
{
    struct cport *cport;

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

    /* Restart the flow of received data */
    unipro_write(REG_RX_PAUSE_SIZE_00 + (cport->cportid * sizeof(uint32_t)),
                 (1 << 31) | CPORT_BUF_SIZE);

    return 0;
}
Esempio n. 7
0
void unipro_switch_rxbuf(unsigned int cportid, void *buffer)
{
    uint32_t ahm_address = AHM_ADDRESS_00;
    struct cport *cport = cport_handle(cportid);

    if (!cport)
        return;

    if (cportid < CPORTID_CDSI0)
        ahm_address += (cportid * sizeof(uint32_t));
    else
        ahm_address += ((cportid - 2) * sizeof(uint32_t));

    cport->rx_buf = buffer;
    unipro_write(ahm_address, (uint32_t) buffer);
}
Esempio n. 8
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;
}
Esempio n. 9
0
/**
 * @brief           send data over UniPro asynchronously (not blocking)
 * @return          0 on success, <0 otherwise
 * @param[in]       cportid: target CPort ID
 * @param[in]       buf: data buffer
 * @param[in]       len: data buffer length (in bytes)
 * @param[in]       callback: function called upon Tx completion
 * @param[in]       priv: optional argument passed to callback
 */
int unipro_send_async(unsigned int cportid, const void *buf, size_t len,
                      unipro_send_completion_t callback, void *priv)
{
    struct cport *cport;
    struct unipro_buffer *buffer;
    irqstate_t flags;

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

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

    if (cport->pending_reset) {
        return -EPIPE;
    }

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

    DEBUGASSERT(TRANSFER_MODE == 2);

    buffer = zalloc(sizeof(*buffer));
    if (!buffer) {
        return -ENOMEM;
    }
    list_init(&buffer->list);
    buffer->som = true;
    buffer->len = len;
    buffer->callback = callback;
    buffer->priv = priv;
    buffer->data = buf;

    flags = irqsave();
    list_add(&cport->tx_fifo, &buffer->list);
    irqrestore(flags);

    sem_post(&worker.tx_fifo_lock);
    return 0;
}
Esempio n. 10
0
/**
 * @brief Register a driver with the unipro core
 * @param drv unipro driver to register
 * @param cportid cport number to associate this driver to
 * @return 0 on success, <0 on error
 */
int unipro_driver_register(struct unipro_driver *driver, unsigned int cportid)
{
    struct cport *cport = cport_handle(cportid);
    if (!cport) {
        return -ENODEV;
    }

    if (cport->driver) {
        lldbg("ERROR: Already registered by: %s\n",
              cport->driver->name);
        return -EEXIST;
    }

    cport->driver = driver;

    lldbg("Registered driver %s on %sconnected CP%u\n",
          cport->driver->name, cport->connected ? "" : "un",
          cport->cportid);
    return 0;
}
Esempio n. 11
0
int unipro_send_async(unsigned int cportid, const void *buf, size_t len,
        unipro_send_completion_t callback, void *priv)
{
    struct cport *cport;
    struct unipro_xfer_descriptor *desc;
    irqstate_t flags;

    cport = cport_handle(cportid);
    if (!cport) {
        lowsyslog("unipro: invalid cport id: %u, dropping message...\n",
                cportid);
        return -EINVAL;
    }

    if (cport->pending_reset) {
        return -EPIPE;
    }

    desc = zalloc(sizeof(*desc));
    if (!desc)
        return -ENOMEM;

    desc->data = buf;
    desc->len = len;
    desc->data_offset = 0;
    desc->callback = callback;
    desc->priv = priv;
    desc->cport = cport;

    list_init(&desc->list);

    flags = irqsave();
    list_add(&cport->tx_fifo, &desc->list);
    irqrestore(flags);

    sem_post(&worker.tx_fifo_lock);

    return 0;
}
Esempio n. 12
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;
}
Esempio n. 13
0
int unipro_reset_cport(unsigned int cportid, cport_reset_completion_cb_t cb,
                       void *priv)
{
    struct cport *cport;

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

    if (cport->pending_reset || cport->reset_completion_cb ||
        cport->reset_completion_cb_priv) {
        return -EINPROGRESS;
    }

    cport->reset_completion_cb_priv = priv;
    cport->reset_completion_cb = cb;
    cport->pending_reset = true;

    unipro_reset_notify(cportid);

    return 0;
}
Esempio n. 14
0
/**
 * @brief Initialize one UniPro cport
 */
static int unipro_init_cport(unsigned int cportid)
{
    struct cport *cport = cport_handle(cportid);

    if (!cport) {
        return -EINVAL;
    }

    if (cport->connected)
        return 0;

    _unipro_reset_cport(cportid);

    atomic_init(&cport->inflight_buf_count, 0);
#if defined(CONFIG_APBRIDGEA)
    cport->max_inflight_buf_count = 1;
#else
    cport->max_inflight_buf_count = CONFIG_TSB_UNIPRO_MAX_INFLIGHT_BUFCOUNT;
#endif
    cport->switch_buf_on_free = false;

    cport->rx_buf = unipro_rxbuf_alloc(cportid);
    if (!cport->rx_buf) {
        lowsyslog("unipro: couldn't allocate initial buffer for CP%u\n",
                  cportid);
        return -ENOMEM;
    }

    unipro_switch_rxbuf(cportid, cport->rx_buf);

#ifdef UNIPRO_DEBUG
    unipro_info();
#endif

    return 0;
}
Esempio n. 15
0
/**
 * @brief Enable a CPort that has a connected connection.
 */
static int configure_connected_cport(unsigned int cportid) {
    int ret = 0;
    struct cport *cport;
    unsigned int rc;
    irqstate_t flags;

    cport = cport_handle(cportid);
    if (!cport) {
        return -EINVAL;
    }
    rc = cport_get_status(cport);
    switch (rc) {
    case CPORT_STATUS_CONNECTED:
        cport->connected = 1;

        /*
         * Clear any pending EOM interrupts, then enable them.
         */
        flags = irqsave();
        clear_int(cportid);
        enable_int(cportid);
        irqrestore(flags);

        /* Start the flow of received data */
        unipro_write(REG_RX_PAUSE_SIZE_00 + (cportid * sizeof(uint32_t)),
                     (1 << 31) | CPORT_BUF_SIZE);
        break;
    case CPORT_STATUS_UNCONNECTED:
        ret = -ENOTCONN;
        break;
    default:
        lldbg("Unexpected status: CP%u: status: 0x%u\n", cportid, rc);
        ret = -EIO;
    }
    return ret;
}
Esempio n. 16
0
/**
 * @brief UniPro debug dump
 */
static void dump_regs(void) {
    uint32_t val;
    unsigned int i;

#define DBG_ATTR(attr) do {                  \
    (void)unipro_attr_local_read(attr, &val, 0); \
    lldbg("    [%s]: 0x%x\n", #attr, val);   \
} while (0);

#define DBG_CPORT_ATTR(attr, cportid) do {         \
    unipro_attr_local_read(attr, &val, cportid); \
    lldbg("    [%s]: 0x%x\n", #attr, val);         \
} while (0);

#define REG_DBG(reg) do {                 \
    val = unipro_read(reg);               \
    lldbg("    [%s]: 0x%x\n", #reg, val); \
} while (0)

    lldbg("DME Attributes\n");
    lldbg("========================================\n");
    DBG_ATTR(PA_ACTIVETXDATALANES);
    DBG_ATTR(PA_ACTIVERXDATALANES);
    DBG_ATTR(PA_TXGEAR);
    DBG_ATTR(PA_TXTERMINATION);
    DBG_ATTR(PA_HSSERIES);
    DBG_ATTR(PA_PWRMODE);
    DBG_ATTR(PA_ACTIVERXDATALANES);
    DBG_ATTR(PA_RXGEAR);
    DBG_ATTR(PA_RXTERMINATION);
    DBG_ATTR(PA_PWRMODEUSERDATA0);
    DBG_ATTR(N_DEVICEID);
    DBG_ATTR(N_DEVICEID_VALID);
    DBG_ATTR(DME_DDBL1_REVISION);
    DBG_ATTR(DME_DDBL1_LEVEL);
    DBG_ATTR(DME_DDBL1_DEVICECLASS);
    DBG_ATTR(DME_DDBL1_MANUFACTURERID);
    DBG_ATTR(DME_DDBL1_PRODUCTID);
    DBG_ATTR(DME_DDBL1_LENGTH);
    DBG_ATTR(TSB_DME_DDBL2_A);
    DBG_ATTR(TSB_DME_DDBL2_B);
    DBG_ATTR(TSB_MAILBOX);
    DBG_ATTR(TSB_MAXSEGMENTCONFIG);
    DBG_ATTR(TSB_DME_POWERMODEIND);

    lldbg("Unipro Interrupt Info:\n");
    lldbg("========================================\n");
    REG_DBG(UNIPRO_INT_EN);
    REG_DBG(AHM_RX_EOM_INT_EN_0);
    REG_DBG(AHM_RX_EOM_INT_EN_1);

    REG_DBG(UNIPRO_INT_BEF);
    REG_DBG(AHS_TIMEOUT_INT_BEF_0);
    REG_DBG(AHS_TIMEOUT_INT_BEF_1);
    REG_DBG(AHM_HRESP_ERR_INT_BEF_0);
    REG_DBG(AHM_HRESP_ERR_INT_BEF_1);
    REG_DBG(CPB_RX_E2EFC_RSLT_ERR_INT_BEF_0);
    REG_DBG(CPB_RX_E2EFC_RSLT_ERR_INT_BEF_1);
    REG_DBG(CPB_TX_RSLTCODE_ERR_INT_BEF_0);
    REG_DBG(CPB_TX_RSLTCODE_ERR_INT_BEF_1);
    REG_DBG(CPB_RX_MSGST_ERR_INT_BEF_0);
    REG_DBG(CPB_RX_MSGST_ERR_INT_BEF_1);
    REG_DBG(LUP_INT_BEF);
    REG_DBG(A2D_ATTRACS_INT_BEF);
    REG_DBG(AHM_RX_EOM_INT_BEF_0);
    REG_DBG(AHM_RX_EOM_INT_BEF_1);
    REG_DBG(AHM_RX_EOM_INT_BEF_2);
    REG_DBG(AHM_RX_EOT_INT_BEF_0);
    REG_DBG(AHM_RX_EOT_INT_BEF_1);

    lldbg("Unipro Registers:\n");
    lldbg("========================================\n");
    REG_DBG(AHM_MODE_CTRL_0);
    if (tsb_get_product_id() == tsb_pid_apbridge) {
        REG_DBG(AHM_MODE_CTRL_1);
        REG_DBG(AHM_MODE_CTRL_2);
    }
    REG_DBG(AHM_ADDRESS_00);
    REG_DBG(REG_RX_PAUSE_SIZE_00);
    REG_DBG(CPB_RX_TRANSFERRED_DATA_SIZE_00);
    REG_DBG(CPB_TX_BUFFER_SPACE_00);
    REG_DBG(CPB_TX_RESULTCODE_0);
    REG_DBG(AHS_HRESP_MODE_0);
    REG_DBG(AHS_TIMEOUT_00);
    REG_DBG(CPB_TX_E2EFC_EN_0);
    REG_DBG(CPB_TX_E2EFC_EN_1);
    REG_DBG(CPB_RX_E2EFC_EN_0);
    REG_DBG(CPB_RX_E2EFC_EN_1);
    REG_DBG(CPORT_STATUS_0);
    REG_DBG(CPORT_STATUS_1);
    REG_DBG(CPORT_STATUS_2);

    lldbg("Connected CPorts:\n");
    lldbg("========================================\n");
    for (i = 0; i < cport_count; i++) {
        struct cport *cport = cport_handle(i);
        if (!cport) {
            continue;
        }

        val = cport_get_status(cport);

        if (val == CPORT_STATUS_CONNECTED) {
            lldbg("CPORT %u:\n", i);
            DBG_CPORT_ATTR(T_PEERDEVICEID, i);
            DBG_CPORT_ATTR(T_PEERCPORTID, i);
            DBG_CPORT_ATTR(T_TRAFFICCLASS, i);
            DBG_CPORT_ATTR(T_CPORTFLAGS, i);
            DBG_CPORT_ATTR(T_LOCALBUFFERSPACE, i);
            DBG_CPORT_ATTR(T_PEERBUFFERSPACE, i);
            DBG_CPORT_ATTR(T_CREDITSTOSEND, i);
            DBG_CPORT_ATTR(T_RXTOKENVALUE, i);
            DBG_CPORT_ATTR(T_TXTOKENVALUE, i);
            DBG_CPORT_ATTR(T_CONNECTIONSTATE, i);
        }
    }

    lldbg("NVIC:\n");
    lldbg("========================================\n");
    tsb_dumpnvic();
}