Example #1
0
/**
 * @brief See ENG-376.
 *
 * We use a mailbox notification from the SVC to solve a race condition
 * involving FCT transmission. When the SVC makes a connection, it sets all the
 * relevant DME parameters as defined in MIPI UniPro 1.6, then pokes the
 * bridge mailbox, telling it that it is safe to send FCTs on a given CPort.
 */
static int mailbox_evt(void)
{
    uint32_t cportid;
    int rc;
    uint32_t e2efc;
    uint32_t val;

    DBG_UNIPRO("mailbox interrupt received\n");

    /*
     * Figure out which CPort to turn on FCT. The desired CPort is always
     * the mailbox value - 1.
     */
    rc = unipro_attr_local_read(TSB_MAILBOX, &cportid, 0);
    if (rc) {
        return rc;
    }
    if (cportid >= cport_count) {
        DBG_UNIPRO("cportid %d in mailbox exceeds count of cports %d\n",
                   cportid, cport_count);
        return -EINVAL;
    }
    cportid--;

    rc = unipro_attr_local_read(T_CPORTFLAGS, &val, cportid);
    if (rc) {
        return rc;
    }
    if (val & CPORT_FLAGS_E2EFC) {
        DBG_UNIPRO("Enabling E2EFC on cport %u\n", cportid);
        if (cportid < 32) {
            e2efc = unipro_read(CPB_RX_E2EFC_EN_0);
            e2efc |= (1 << cportid);
            unipro_write(CPB_RX_E2EFC_EN_0, e2efc);
        } else if (cportid < 64) {
            e2efc = unipro_read(CPB_RX_E2EFC_EN_1);
            e2efc |= (1 << (cportid - 32));
            unipro_write(CPB_RX_E2EFC_EN_1, e2efc);
        }
    }

    configure_connected_cport(cportid);

    /* Acknowledge the mailbox write */
    rc = tsb_unipro_mbox_ack(cportid + 1);
    if (rc) {
        return rc;
    }

    return 0;
}
Example #2
0
static int irq_unipro(int irq, void *context) {
    int rc;
    uint32_t val;

    tsb_irq_clear_pending(TSB_IRQ_UNIPRO);

    if (unipro_read(LUP_INT_BEF) & UNIPRO_LUP_DONE) {
        unipro_write(LUP_INT_BEF, UNIPRO_LUP_DONE);
        unipro_evt_handler(UNIPRO_EVT_LUP_DONE);
     }

    /*
     * Clear the initial interrupt
     */
    rc = unipro_attr_local_read(TSB_INTERRUPTSTATUS, &val, 0);
    if (rc) {
        goto done;
    }

    if (val & TSB_INTERRUPTSTATUS_MAILBOX) {
        unipro_evt_handler(UNIPRO_EVT_MAILBOX);
    }

done:
    return 0;
}
Example #3
0
static int es3_tsb_unipro_set_init_status(uint32_t val)
{
    int retval;
    uint32_t status;

    /*
     * See SW-1228
     *  -> https://projectara.atlassian.net/browse/SW-1228?focusedCommentId=28889&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-28889
     */
    if (val & INIT_STATUS_ERROR_CODE_MASK) {
        lowsyslog("%s() cannot override the init status error code (init status: %u).\n",
                  __func__, val);
        return -EINVAL;
    }

    retval = unipro_attr_local_read(TSB_DME_ES3_INIT_STATUS, &status,
                                    UNIPRO_SELINDEX_NULL);
    if (retval) {
        lowsyslog("init-status read failed: retval = %d\n", retval);
        return retval;
    }

    /* preserve error code: see SW-1228 */
    val |= status & INIT_STATUS_ERROR_CODE_MASK;

    retval = unipro_attr_local_write(TSB_DME_ES3_INIT_STATUS, val,
                                     UNIPRO_SELINDEX_NULL);
    if (retval) {
        lowsyslog("init-status write failed: retval = %d\n", retval);
        return retval;
    }

    return 0;
}
Example #4
0
static int unipro_enable_mailbox_irq(void)
{
    int retval;
    uint32_t val;

    retval = unipro_attr_local_read(TSB_INTERRUPTENABLE, &val,
                                    UNIPRO_SELINDEX_NULL);
    if (retval) {
        return retval;
    }

    return unipro_attr_local_write(TSB_INTERRUPTENABLE,
                                   val | TSB_INTERRUPTSTATUS_MAILBOX,
                                   UNIPRO_SELINDEX_NULL);
}
Example #5
0
unsigned int unipro_cport_count(void) {
    uint32_t num_cports;
    int retval;

    if (tsb_get_rev_id() == tsb_rev_es2) { /* T_NUMCPORTS is incorrect on es2 */
        /*
         * Reduce the run-time CPort count to what's available on the
         * GPBridges, unless we can determine that we're running on an
         * APBridge.
         */
        return ((tsb_get_product_id() == tsb_pid_apbridge) ?
                ES2_APBRIDGE_CPORT_MAX : ES2_GPBRIDGE_CPORT_MAX);
    }

    retval = unipro_attr_local_read(T_NUMCPORTS, &num_cports, 0);
    if (retval) {
        lowsyslog("unipro: cannot determine number of cports\n");
        return 0;
    }

    return num_cports;
}
Example #6
0
/* IMPORTANT:
 * The UniPro event handler callback runs in the context of the UniPro IRQ. */
static void unipro_evt_handler(enum unipro_event evt)
{
    uint32_t rc;
    uint32_t v = 0;
    int err;

    llvdbg("event=%d\n", evt);

    switch (evt) {
    case UNIPRO_EVT_LUP_DONE:
        svc_send_event(SVC_EVENT_UNIPRO_LINK_UP, 0, 0, 0);
        break;
    case UNIPRO_EVT_LINK_LOST:
        rc = unipro_attr_local_read(TSB_DME_LINKLOSTIND, &v, 0);
        llvdbg("rc=%d, lost_ind=%x\n", rc, v);

        if (v & 0x1) {
            svc_send_event(SVC_EVENT_UNIPRO_LINK_DOWN,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0);
        }

        break;
    case UNIPRO_EVT_PWRMODE:
        if (g_svc.gearbox) {
            uint32_t pmi_val0 = 0;
            rc = unipro_attr_read(TSB_DME_POWERMODEIND, &pmi_val0, 0, 0);
            llvdbg("rc=%d, pmi0=%x\n", rc, pmi_val0);

            uint32_t pmi_val1 = 0;
            rc = unipro_attr_read(TSB_DME_POWERMODEIND, &pmi_val1, 0, 1);
            llvdbg("rc=%d, pmi1=%x\n", rc, pmi_val1);

            if (pmi_val0 == 2 && pmi_val1 == 4) {
                llvdbg("Powermode change successful\n");
                err = 0;
            } else {
                llvdbg("Powermode change failed\n");
                err = -1;
            }

            svc_send_event(SVC_EVENT_GEAR_SHIFT_DONE,
                (void *)(unsigned int)err,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0);
        }
        break;
    case UNIPRO_EVT_PHY_ERROR:
        rc = unipro_attr_local_read(TSB_DME_ERRORPHYIND, &v, 0);
        v &= 1;
        if (v) {
            llvdbg("rc=%d, phy err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.phy_lane_err, v);
        }
        break;
    case UNIPRO_EVT_PA_ERROR:
        rc = unipro_attr_local_read(TSB_DME_ERRORPAIND, &v, 0);
        v &= 0x3;
        if (v) {
            llvdbg("rc=%d, pa err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.pa_lane_reset_tx, v);
        }
        break;
    case UNIPRO_EVT_D_ERROR:
        rc = unipro_attr_local_read(TSB_DME_ERRORDIND, &v, 0);
        v &= 0x7fff;
        if (v) {
            llvdbg("rc=%d, d err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.d_nac_received, v);
        }
        break;
    case UNIPRO_EVT_N_ERROR:
        rc = unipro_attr_local_read(TSB_DME_ERRORNIND, &v, 0);
        v &= 0x7;
        if (v) {
            llvdbg("rc=%d, n err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.n_unsupported_header_type, v);
        }
        break;
    case UNIPRO_EVT_T_ERROR:
        rc = unipro_attr_local_read(TSB_DME_ERRORTIND, &v, 0);
        v &= 0x7f;
        if (v) {
            llvdbg("rc=%d, t err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.t_unsupported_header_type, v);
        }
        break;
    case UNIPRO_EVT_PAINIT_ERROR: {
        bool lost = false;

        rc = unipro_attr_local_read(TSB_DME_ERRORPHYIND, &v, 0);
        v &= 0x1;
        if (v) {
            llvdbg("rc=%d, phy err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.phy_lane_err, v);
            lost = true;
        }

        rc = unipro_attr_local_read(TSB_DME_ERRORPAIND, &v, 0);
        v &= 0x3;
        if (v) {
            llvdbg("rc=%d, pa err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.pa_lane_reset_tx, v);
            lost = true;
        }

        rc = unipro_attr_local_read(TSB_DME_ERRORDIND, &v, 0);
        v &= 0x7fff;
        if (v) {
            llvdbg("rc=%d, d err=%x\n", rc, v);
            _svc_bitmask_to_stats(&g_unipro_stats.d_nac_received, v);
            lost = true;
        }

        if (lost) {
            llvdbg("Link lost\n");
            svc_send_event(SVC_EVENT_UNIPRO_LINK_DOWN,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0);
        }

        break;
    }
    case UNIPRO_EVT_MAILBOX: {
        v = TSB_MAIL_RESET;
        rc = unipro_attr_local_read(TSB_MAILBOX, &v, 0);
        llvdbg("rc=%d, mbox_val=%d\n", rc, v);

        if (rc) {
        }

#if CONFIG_UNIPRO_P2P_APBA
        if (v == TSB_MAIL_READY_OTHER) {
            llvdbg("Mod detected\n");
            svc_send_event(SVC_EVENT_MOD_DETECTED,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0,
                (void *)(unsigned int)0);
        } else {
            // TODO: Handle error case.
            llvdbg("Mod NOT detected\n");
        }
#elif CONFIG_UNIPRO_P2P_APBE
        llvdbg("Connected cport %d\n", v-1);
        svc_send_event(SVC_EVENT_CPORTS_DONE, (void *)(v-1), 0, 0);
#endif

        break;
    }
    default:
        break;
    }

    vdbg("done\n");
}