Path: blob/master/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
26481 views
/***********************license start***************1* Author: Cavium Networks2*3* Contact: [email protected]4* This file is part of the OCTEON SDK5*6* Copyright (c) 2003-2008 Cavium Networks7*8* This file is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License, Version 2, as10* published by the Free Software Foundation.11*12* This file is distributed in the hope that it will be useful, but13* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty14* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or15* NONINFRINGEMENT. See the GNU General Public License for more16* details.17*18* You should have received a copy of the GNU General Public License19* along with this file; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21* or visit http://www.gnu.org/licenses/.22*23* This file may also be available under a different license from Cavium.24* Contact Cavium Networks for more information25***********************license end**************************************/2627/*28* Support functions for managing command queues used for29* various hardware blocks.30*/3132#include <linux/kernel.h>3334#include <asm/octeon/octeon.h>3536#include <asm/octeon/cvmx-config.h>37#include <asm/octeon/cvmx-fpa.h>38#include <asm/octeon/cvmx-cmd-queue.h>3940#include <asm/octeon/cvmx-npei-defs.h>41#include <asm/octeon/cvmx-pexp-defs.h>42#include <asm/octeon/cvmx-pko-defs.h>4344/*45* This application uses this pointer to access the global queue46* state. It points to a bootmem named block.47*/48__cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;49EXPORT_SYMBOL_GPL(__cvmx_cmd_queue_state_ptr);5051/*52* Initialize the Global queue state pointer.53*54* Returns CVMX_CMD_QUEUE_SUCCESS or a failure code55*/56static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void)57{58char *alloc_name = "cvmx_cmd_queues";59extern uint64_t octeon_reserve32_memory;6061if (likely(__cvmx_cmd_queue_state_ptr))62return CVMX_CMD_QUEUE_SUCCESS;6364if (octeon_reserve32_memory)65__cvmx_cmd_queue_state_ptr =66cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr),67octeon_reserve32_memory,68octeon_reserve32_memory +69(CONFIG_CAVIUM_RESERVE32 <<7020) - 1, 128, alloc_name);71else72__cvmx_cmd_queue_state_ptr =73cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr),74128,75alloc_name);76if (__cvmx_cmd_queue_state_ptr)77memset(__cvmx_cmd_queue_state_ptr, 0,78sizeof(*__cvmx_cmd_queue_state_ptr));79else {80struct cvmx_bootmem_named_block_desc *block_desc =81cvmx_bootmem_find_named_block(alloc_name);82if (block_desc)83__cvmx_cmd_queue_state_ptr =84cvmx_phys_to_ptr(block_desc->base_addr);85else {86cvmx_dprintf87("ERROR: cvmx_cmd_queue_initialize: Unable to get named block %s.\n",88alloc_name);89return CVMX_CMD_QUEUE_NO_MEMORY;90}91}92return CVMX_CMD_QUEUE_SUCCESS;93}9495/*96* Initialize a command queue for use. The initial FPA buffer is97* allocated and the hardware unit is configured to point to the98* new command queue.99*100* @queue_id: Hardware command queue to initialize.101* @max_depth: Maximum outstanding commands that can be queued.102* @fpa_pool: FPA pool the command queues should come from.103* @pool_size: Size of each buffer in the FPA pool (bytes)104*105* Returns CVMX_CMD_QUEUE_SUCCESS or a failure code106*/107cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,108int max_depth, int fpa_pool,109int pool_size)110{111__cvmx_cmd_queue_state_t *qstate;112cvmx_cmd_queue_result_t result = __cvmx_cmd_queue_init_state_ptr();113if (result != CVMX_CMD_QUEUE_SUCCESS)114return result;115116qstate = __cvmx_cmd_queue_get_state(queue_id);117if (qstate == NULL)118return CVMX_CMD_QUEUE_INVALID_PARAM;119120/*121* We artificially limit max_depth to 1<<20 words. It is an122* arbitrary limit.123*/124if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH) {125if ((max_depth < 0) || (max_depth > 1 << 20))126return CVMX_CMD_QUEUE_INVALID_PARAM;127} else if (max_depth != 0)128return CVMX_CMD_QUEUE_INVALID_PARAM;129130if ((fpa_pool < 0) || (fpa_pool > 7))131return CVMX_CMD_QUEUE_INVALID_PARAM;132if ((pool_size < 128) || (pool_size > 65536))133return CVMX_CMD_QUEUE_INVALID_PARAM;134135/* See if someone else has already initialized the queue */136if (qstate->base_ptr_div128) {137if (max_depth != (int)qstate->max_depth) {138cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "139"Queue already initialized with different "140"max_depth (%d).\n",141(int)qstate->max_depth);142return CVMX_CMD_QUEUE_INVALID_PARAM;143}144if (fpa_pool != qstate->fpa_pool) {145cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "146"Queue already initialized with different "147"FPA pool (%u).\n",148qstate->fpa_pool);149return CVMX_CMD_QUEUE_INVALID_PARAM;150}151if ((pool_size >> 3) - 1 != qstate->pool_size_m1) {152cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "153"Queue already initialized with different "154"FPA pool size (%u).\n",155(qstate->pool_size_m1 + 1) << 3);156return CVMX_CMD_QUEUE_INVALID_PARAM;157}158CVMX_SYNCWS;159return CVMX_CMD_QUEUE_ALREADY_SETUP;160} else {161union cvmx_fpa_ctl_status status;162void *buffer;163164status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS);165if (!status.s.enb) {166cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "167"FPA is not enabled.\n");168return CVMX_CMD_QUEUE_NO_MEMORY;169}170buffer = cvmx_fpa_alloc(fpa_pool);171if (buffer == NULL) {172cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "173"Unable to allocate initial buffer.\n");174return CVMX_CMD_QUEUE_NO_MEMORY;175}176177memset(qstate, 0, sizeof(*qstate));178qstate->max_depth = max_depth;179qstate->fpa_pool = fpa_pool;180qstate->pool_size_m1 = (pool_size >> 3) - 1;181qstate->base_ptr_div128 = cvmx_ptr_to_phys(buffer) / 128;182/*183* We zeroed the now serving field so we need to also184* zero the ticket.185*/186__cvmx_cmd_queue_state_ptr->187ticket[__cvmx_cmd_queue_get_index(queue_id)] = 0;188CVMX_SYNCWS;189return CVMX_CMD_QUEUE_SUCCESS;190}191}192193/*194* Shutdown a queue and free its command buffers to the FPA. The195* hardware connected to the queue must be stopped before this196* function is called.197*198* @queue_id: Queue to shutdown199*200* Returns CVMX_CMD_QUEUE_SUCCESS or a failure code201*/202cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id)203{204__cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);205if (qptr == NULL) {206cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Unable to "207"get queue information.\n");208return CVMX_CMD_QUEUE_INVALID_PARAM;209}210211if (cvmx_cmd_queue_length(queue_id) > 0) {212cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Queue still "213"has data in it.\n");214return CVMX_CMD_QUEUE_FULL;215}216217__cvmx_cmd_queue_lock(queue_id, qptr);218if (qptr->base_ptr_div128) {219cvmx_fpa_free(cvmx_phys_to_ptr220((uint64_t) qptr->base_ptr_div128 << 7),221qptr->fpa_pool, 0);222qptr->base_ptr_div128 = 0;223}224__cvmx_cmd_queue_unlock(qptr);225226return CVMX_CMD_QUEUE_SUCCESS;227}228229/*230* Return the number of command words pending in the queue. This231* function may be relatively slow for some hardware units.232*233* @queue_id: Hardware command queue to query234*235* Returns Number of outstanding commands236*/237int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id)238{239if (CVMX_ENABLE_PARAMETER_CHECKING) {240if (__cvmx_cmd_queue_get_state(queue_id) == NULL)241return CVMX_CMD_QUEUE_INVALID_PARAM;242}243244/*245* The cast is here so gcc with check that all values in the246* cvmx_cmd_queue_id_t enumeration are here.247*/248switch ((cvmx_cmd_queue_id_t) (queue_id & 0xff0000)) {249case CVMX_CMD_QUEUE_PKO_BASE:250/*251* FIXME: Need atomic lock on252* CVMX_PKO_REG_READ_IDX. Right now we are normally253* called with the queue lock, so that is a SLIGHT254* amount of protection.255*/256cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue_id & 0xffff);257if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {258union cvmx_pko_mem_debug9 debug9;259debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);260return debug9.cn38xx.doorbell;261} else {262union cvmx_pko_mem_debug8 debug8;263debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);264return debug8.cn50xx.doorbell;265}266case CVMX_CMD_QUEUE_ZIP:267case CVMX_CMD_QUEUE_DFA:268case CVMX_CMD_QUEUE_RAID:269/* FIXME: Implement other lengths */270return 0;271case CVMX_CMD_QUEUE_DMA_BASE:272{273union cvmx_npei_dmax_counts dmax_counts;274dmax_counts.u64 =275cvmx_read_csr(CVMX_PEXP_NPEI_DMAX_COUNTS276(queue_id & 0x7));277return dmax_counts.s.dbell;278}279case CVMX_CMD_QUEUE_END:280return CVMX_CMD_QUEUE_INVALID_PARAM;281}282return CVMX_CMD_QUEUE_INVALID_PARAM;283}284285/*286* Return the command buffer to be written to. The purpose of this287* function is to allow CVMX routine access to the low level buffer288* for initial hardware setup. User applications should not call this289* function directly.290*291* @queue_id: Command queue to query292*293* Returns Command buffer or NULL on failure294*/295void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id)296{297__cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);298if (qptr && qptr->base_ptr_div128)299return cvmx_phys_to_ptr((uint64_t) qptr->base_ptr_div128 << 7);300else301return NULL;302}303304305