/** * @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; }
/** * @INTERNAL * Bringup and enable a LOOP 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_loop_enable(int interface) { cvmx_pip_prt_cfgx_t port_cfg; int num_ports, index; unsigned long offset; num_ports = __cvmx_helper_get_num_ipd_ports(interface); /* * We need to disable length checking so packet < 64 bytes and jumbo * frames don't get errors */ for (index = 0; index < num_ports; index++) { offset = ((octeon_has_feature(OCTEON_FEATURE_PKND)) ? cvmx_helper_get_pknd(interface, index) : cvmx_helper_get_ipd_port(interface, index)); port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(offset)); port_cfg.s.maxerr_en = 0; port_cfg.s.minerr_en = 0; cvmx_write_csr(CVMX_PIP_PRT_CFGX(offset), port_cfg.u64); } /* * Disable FCS stripping for loopback ports */ if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs; ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); ipd_sub_port_fcs.s.port_bit2 = 0; cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); } return 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; }