/** * @INTERNAL * Allocate memory for and initialize a single FPA pool. * * @param pool Pool to initialize * @param buffer_size Size of buffers to allocate in bytes * @param buffers Number of buffers to put in the pool. Zero is allowed * @param name String name of the pool for debugging purposes * @return Zero on success, non-zero on failure */ static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size, uint64_t buffers, const char *name) { uint64_t current_num; void *memory; uint64_t align = CVMX_CACHE_LINE_SIZE; /* Align the allocation so that power of 2 size buffers are naturally aligned */ while (align < buffer_size) align = align << 1; if (buffers == 0) return 0; current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool)); if (current_num) { cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. Skipping setup.\n", pool, name, (unsigned long long)current_num); return 0; } memory = cvmx_bootmem_alloc(buffer_size * buffers, align); if (memory == NULL) { cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n", pool, name); return -1; } cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers); 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; }