/**
 * @INTERNAL
 * Bringup and enable a NPI interface. After this call packet
 * I/O should be fully functional. This is called with IPD
 * enabled but PKO disabled.
 *
 * @param interface Interface to bring up
 *
 * @return Zero on success, negative on failure
 */
int __cvmx_helper_npi_enable(int interface)
{
	int port;
	int num_ports = cvmx_helper_ports_on_interface(interface);

	if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
		/*
		 * Enables are controlled by the remote host, so
		 * nothing to do here.
		 */
		return 0;

	/*
	 * On CN50XX, CN52XX, and CN56XX we need to disable length
	 * checking so packet < 64 bytes and jumbo frames don't get
	 * errors.
	 */
	for (port = 0; port < num_ports; port++) {
		union cvmx_pip_prt_cfgx port_cfg;
		int ipd_port = (OCTEON_IS_MODEL(OCTEON_CN68XX)) ? cvmx_helper_get_pknd(interface, port) : cvmx_helper_get_ipd_port(interface, port);
		port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
		port_cfg.s.lenerr_en = 0;
		port_cfg.s.maxerr_en = 0;
		port_cfg.s.minerr_en = 0;
		cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64);

		if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
			/* Set up pknd and bpid */
			union cvmx_sli_portx_pkind config;
			config.u64 = cvmx_read_csr(CVMX_PEXP_SLI_PORTX_PKIND(port));
			config.s.bpkind = cvmx_helper_get_bpid(interface, port);
			config.s.pkind = cvmx_helper_get_pknd(interface, port);
			cvmx_write_csr(CVMX_PEXP_SLI_PORTX_PKIND(port), config.u64);
		}
	}

	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
		/*
		 * Set up pko pipes.
		 */
		union cvmx_sli_tx_pipe config;
		config.u64 = cvmx_read_csr(CVMX_PEXP_SLI_TX_PIPE);
		config.s.base = __cvmx_pko_get_pipe(interface, 0);
		config.s.nump = cvmx_npi_num_pipes < 0 ? num_ports : cvmx_npi_num_pipes;
		cvmx_write_csr(CVMX_PEXP_SLI_TX_PIPE, config.u64);
	}

	/* Enables are controlled by the remote host, so nothing to do here */
	return 0;
}
Ejemplo n.º 2
0
/**
 * @INTERNAL
 * Probe a ILK interface and determine the number of ports
 * connected to it. The ILK interface should still be down
 * after this call.
 *
 * @param interface Interface to probe
 *
 * @return Number of ports on the interface. Zero to disable.
 */
int __cvmx_helper_ilk_probe(int interface)
{
    int i, j, res = -1;
    static int pipe_base = 0, pknd_base = 0;
    static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp;
    static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1;
    static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2;

    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
        return 0;

    interface -= CVMX_ILK_GBL_BASE;
    if (interface >= CVMX_NUM_ILK_INTF)
        return 0;

    /* the configuration should be done only once */
    if (cvmx_ilk_get_intf_ena (interface))
        return cvmx_ilk_chans[interface];

    /* configure lanes and enable the link */
    res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]);
    if (res < 0)
        return 0;

    /* set up the group of pipes available to ilk */
    if (pipe_base == 0)
        pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0);

    if (pipe_base == -1)
    {
        pipe_base = 0;
        return 0;
    }

    res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]);
    if (res < 0)
        return 0;

    /* set up pipe to channel mapping */
    i = pipe_base;
    if (pch == NULL)
    {
        pch = (cvmx_ilk_pipe_chan_t *)
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
        kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL);
#else
        cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t),
                            sizeof(cvmx_ilk_pipe_chan_t));
#endif
        if (pch == NULL)
            return 0;
    }

    memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t));
    tmp = pch;
    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
    {
        tmp->pipe = i++;
        tmp->chan = cvmx_ilk_chan_map[interface][j];
        tmp++;
    }
    res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]);
    if (res < 0)
    {
        res = 0;
        goto err_free_pch;
    }
    pipe_base += cvmx_ilk_chans[interface];

    /* set up channel to pkind mapping */
    if (pknd_base == 0)
        pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0);

    i = pknd_base;
    if (chpknd == NULL)
    {
        chpknd = (cvmx_ilk_chan_pknd_t *)
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
        kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL);
#else
        cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t),
                            sizeof(cvmx_ilk_chan_pknd_t));
#endif
        if (chpknd == NULL)
        {
            pipe_base -= cvmx_ilk_chans[interface];
            res = 0;
            goto err_free_pch;
        }
    }

    memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t));
    tmp1 = chpknd;
    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
    {
        tmp1->chan = cvmx_ilk_chan_map[interface][j];
        tmp1->pknd = i++;
        tmp1++;
    }
    res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]);
    if (res < 0)
    {
        pipe_base -= cvmx_ilk_chans[interface];
        res = 0;
        goto err_free_chpknd;
    }
    pknd_base += cvmx_ilk_chans[interface];

    /* Set up tx calendar */
    if (calent == NULL)
    {
        calent = (cvmx_ilk_cal_entry_t *)
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
        kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL);
#else
        cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t),
                            sizeof(cvmx_ilk_cal_entry_t));
#endif
        if (calent == NULL)
        {
            pipe_base -= cvmx_ilk_chans[interface];
            pknd_base -= cvmx_ilk_chans[interface];
            res = 0;
            goto err_free_chpknd;
        }
    }

    memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
    tmp1 = chpknd;
    tmp2 = calent;
    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
    {
        tmp2->pipe_bpid = tmp1->pknd;
        tmp2->ent_ctrl = PIPE_BPID;
        tmp1++;
        tmp2++;
    }
    res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface],
                                 calent, 1);
    if (res < 0)
    {
        pipe_base -= cvmx_ilk_chans[interface];
        pknd_base -= cvmx_ilk_chans[interface];
        res = 0;
        goto err_free_calent;
    }

    /* set up rx calendar. allocated memory can be reused.
     * this is because max pkind is always less than max pipe */
    memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
    tmp = pch;
    tmp2 = calent;
    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
    {
        tmp2->pipe_bpid = tmp->pipe;
        tmp2->ent_ctrl = PIPE_BPID;
        tmp++;
        tmp2++;
    }
    res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface],
                                 calent, CVMX_ILK_RX_FIFO_WM, 1);
    if (res < 0)
    {
        pipe_base -= cvmx_ilk_chans[interface];
        pknd_base -= cvmx_ilk_chans[interface];
        res = 0;
        goto err_free_calent;
    }
    res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE);

    goto out;

err_free_calent:
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
    kfree (calent);
#else
    /* no free() for cvmx_bootmem_alloc() */
#endif

err_free_chpknd:
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
    kfree (chpknd);
#else
    /* no free() for cvmx_bootmem_alloc() */ 
#endif

err_free_pch:
#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
    kfree (pch);
#else
    /* no free() for cvmx_bootmem_alloc() */ 
#endif
out:
    return res;
}