1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett/** 41210284Sjmallett * @file 42210284Sjmallett * 43210284Sjmallett * Support library for the hardware Packet Output unit. 44210284Sjmallett * 45232812Sjmallett * <hr>$Revision: 70030 $<hr> 46210284Sjmallett */ 47215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 48215990Sjmallett#include <asm/octeon/cvmx.h> 49215990Sjmallett#include <asm/octeon/cvmx-config.h> 50215990Sjmallett#include <asm/octeon/cvmx-pko.h> 51215990Sjmallett#include <asm/octeon/cvmx-helper.h> 52232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h> 53215990Sjmallett#include <asm/octeon/cvmx-clock.h> 54215990Sjmallett#else 55215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 56215990Sjmallett#include "executive-config.h" 57215990Sjmallett#endif 58210284Sjmallett#include "cvmx.h" 59215990Sjmallett#include "cvmx-sysinfo.h" 60215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 61215990Sjmallett#include "cvmx-config.h" 62215990Sjmallett#endif 63210284Sjmallett#include "cvmx-pko.h" 64210284Sjmallett#include "cvmx-helper.h" 65232812Sjmallett#include "cvmx-helper-cfg.h" 66215990Sjmallett#endif 67210284Sjmallett 68232812Sjmallett/* #define PKO_DEBUG */ 69232812Sjmallett 70232812Sjmallett#define CVMX_PKO_NQ_PER_PORT_MAX 32 71232812Sjmallett 72210284Sjmallett/** 73210284Sjmallett * Internal state of packet output 74210284Sjmallett */ 75210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 76210284Sjmallett 77232812Sjmallett/* 78232812Sjmallett * PKO port iterator 79232812Sjmallett */ 80232812Sjmallett#define CVMX_PKO_FOR_EACH_PORT_BEGIN do { \ 81232812Sjmallett int XIT_pko_port; \ 82232812Sjmallett for (XIT_pko_port = 0; XIT_pko_port < CVMX_HELPER_CFG_MAX_PKO_PORT; \ 83232812Sjmallett XIT_pko_port++) \ 84232812Sjmallett { \ 85232812Sjmallett if (__cvmx_helper_cfg_pko_queue_base(XIT_pko_port) != \ 86232812Sjmallett CVMX_HELPER_CFG_INVALID_VALUE) 87232812Sjmallett 88232812Sjmallett#define CVMX_PKO_FOR_EACH_PORT_END } /* for */ \ 89232812Sjmallett } while (0) 90232812Sjmallett 91232812Sjmallett/* 92232812Sjmallett * @INTERNAL 93232812Sjmallett * 94232812Sjmallett * Get INT for a port 95232812Sjmallett * 96232812Sjmallett * @param interface 97232812Sjmallett * @param index 98232812Sjmallett * @return the INT value on success and -1 on error 99232812Sjmallett */ 100232812Sjmallettstatic int __cvmx_pko_int(int interface, int index) 101232812Sjmallett{ 102232812Sjmallett cvmx_helper_cfg_assert(interface < CVMX_HELPER_CFG_MAX_IFACE); 103232812Sjmallett cvmx_helper_cfg_assert(index >= 0); 104232812Sjmallett 105232812Sjmallett switch (interface) 106232812Sjmallett { 107232812Sjmallett case 0: 108232812Sjmallett cvmx_helper_cfg_assert(index < 4); 109232812Sjmallett return index; 110232812Sjmallett break; 111232812Sjmallett case 1: 112232812Sjmallett cvmx_helper_cfg_assert(index == 0); 113232812Sjmallett return 4; 114232812Sjmallett break; 115232812Sjmallett case 2: 116232812Sjmallett cvmx_helper_cfg_assert(index < 4); 117232812Sjmallett return index + 8; 118232812Sjmallett break; 119232812Sjmallett case 3: 120232812Sjmallett cvmx_helper_cfg_assert(index < 4); 121232812Sjmallett return index + 0xC; 122232812Sjmallett break; 123232812Sjmallett case 4: 124232812Sjmallett cvmx_helper_cfg_assert(index < 4); 125232812Sjmallett return index + 0x10; 126232812Sjmallett break; 127232812Sjmallett case 5: 128232812Sjmallett cvmx_helper_cfg_assert(index < 256); 129232812Sjmallett return 0x1C; 130232812Sjmallett break; 131232812Sjmallett case 6: 132232812Sjmallett cvmx_helper_cfg_assert(index < 256); 133232812Sjmallett return 0x1D; 134232812Sjmallett break; 135232812Sjmallett case 7: 136232812Sjmallett cvmx_helper_cfg_assert(index < 32); 137232812Sjmallett return 0x1E; 138232812Sjmallett break; 139232812Sjmallett case 8: 140232812Sjmallett cvmx_helper_cfg_assert(index < 8); 141232812Sjmallett return 0x1F; 142232812Sjmallett break; 143232812Sjmallett } 144232812Sjmallett 145232812Sjmallett return -1; 146232812Sjmallett} 147232812Sjmallett 148232812Sjmallettint cvmx_pko_get_base_pko_port(int interface, int index) 149232812Sjmallett{ 150232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 151232812Sjmallett return __cvmx_helper_cfg_pko_port_base(interface, index); 152232812Sjmallett else 153232812Sjmallett return cvmx_helper_get_ipd_port(interface, index); 154232812Sjmallett} 155232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 156232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_base_pko_port); 157232812Sjmallett#endif 158232812Sjmallett 159232812Sjmallettint cvmx_pko_get_num_pko_ports(int interface, int index) 160232812Sjmallett{ 161232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 162232812Sjmallett return __cvmx_helper_cfg_pko_port_num(interface, index); 163232812Sjmallett else 164232812Sjmallett return 1; 165232812Sjmallett} 166232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 167232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_num_pko_ports); 168232812Sjmallett#endif 169232812Sjmallett 170232812Sjmallettint cvmx_pko_get_base_queue(int port) 171232812Sjmallett{ 172232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 173232812Sjmallett { 174232812Sjmallett return __cvmx_helper_cfg_pko_queue_base( 175232812Sjmallett cvmx_helper_cfg_ipd2pko_port_base(port)); 176232812Sjmallett } 177232812Sjmallett else 178232812Sjmallett return cvmx_pko_get_base_queue_per_core(port, 0); 179232812Sjmallett} 180232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 181232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_base_queue); 182232812Sjmallett#endif 183232812Sjmallett 184210284Sjmallett/** 185232812Sjmallett * For a given PKO port number, return the base output queue 186232812Sjmallett * for the port. 187232812Sjmallett * 188232812Sjmallett * @param pko_port PKO port number 189232812Sjmallett * @return Base output queue 190232812Sjmallett */ 191232812Sjmallettint cvmx_pko_get_base_queue_pkoid(int pko_port) 192232812Sjmallett{ 193232812Sjmallett return __cvmx_helper_cfg_pko_queue_base(pko_port); 194232812Sjmallett} 195232812Sjmallett 196232812Sjmallett/** 197232812Sjmallett * For a given PKO port number, return the number of output queues 198232812Sjmallett * for the port. 199232812Sjmallett * 200232812Sjmallett * @param pko_port PKO port number 201232812Sjmallett * @return the number of output queues 202232812Sjmallett */ 203232812Sjmallettint cvmx_pko_get_num_queues_pkoid(int pko_port) 204232812Sjmallett{ 205232812Sjmallett return __cvmx_helper_cfg_pko_queue_num(pko_port); 206232812Sjmallett} 207232812Sjmallett 208232812Sjmallettint cvmx_pko_get_num_queues(int port) 209232812Sjmallett{ 210232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 211232812Sjmallett { 212232812Sjmallett return __cvmx_helper_cfg_pko_queue_num( 213232812Sjmallett cvmx_helper_cfg_ipd2pko_port_base(port)); 214232812Sjmallett } 215232812Sjmallett else 216232812Sjmallett { 217232812Sjmallett if (port < 16) 218232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0; 219232812Sjmallett else if (port < 32) 220232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1; 221232812Sjmallett else if (port < 36) 222232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_PCI; 223232812Sjmallett else if (port < 40) 224232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_LOOP; 225232812Sjmallett else if (port < 42) 226232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_SRIO0; 227232812Sjmallett else if (port < 44) 228232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_SRIO1; 229232812Sjmallett else if (port < 46) 230232812Sjmallett return CVMX_PKO_QUEUES_PER_PORT_SRIO2; 231232812Sjmallett } 232232812Sjmallett return 0; 233232812Sjmallett} 234232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 235232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_num_queues); 236232812Sjmallett#endif 237232812Sjmallett 238232812Sjmallett#ifdef PKO_DEBUG 239232812Sjmallett/** 240232812Sjmallett * Show queues for the internal ports 241232812Sjmallett */ 242232812Sjmallettvoid cvmx_pko_show_queue_map(void) 243232812Sjmallett{ 244232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 245232812Sjmallett { 246232812Sjmallett CVMX_PKO_FOR_EACH_PORT_BEGIN { 247232812Sjmallett cvmx_dprintf("pko_port %d (interface%d index%d) has %d queues (queue base = %d)\n", 248232812Sjmallett XIT_pko_port, 249232812Sjmallett __cvmx_helper_cfg_pko_port_interface(XIT_pko_port), 250232812Sjmallett __cvmx_helper_cfg_pko_port_index(XIT_pko_port), 251232812Sjmallett __cvmx_helper_cfg_pko_queue_num(XIT_pko_port), 252232812Sjmallett __cvmx_helper_cfg_pko_queue_base(XIT_pko_port)); 253232812Sjmallett } CVMX_PKO_FOR_EACH_PORT_END; 254232812Sjmallett } 255232812Sjmallett else 256232812Sjmallett { 257232812Sjmallett int core, port; 258232812Sjmallett int pko_output_ports; 259232812Sjmallett 260232812Sjmallett pko_output_ports = 36; 261232812Sjmallett cvmx_dprintf("port"); 262232812Sjmallett for(port = 0; port < pko_output_ports; port++) 263232812Sjmallett cvmx_dprintf("%3d ", port); 264232812Sjmallett cvmx_dprintf("\n"); 265232812Sjmallett 266232812Sjmallett for(core = 0; core < CVMX_MAX_CORES; core++) 267232812Sjmallett { 268232812Sjmallett cvmx_dprintf("\n%2d: ", core); 269232812Sjmallett for(port = 0; port < pko_output_ports; port++) 270232812Sjmallett cvmx_dprintf("%3d ", 271232812Sjmallett cvmx_pko_get_base_queue_per_core(port, core)); 272232812Sjmallett } 273232812Sjmallett cvmx_dprintf("\n"); 274232812Sjmallett 275232812Sjmallett } 276232812Sjmallett} 277232812Sjmallett#endif /* PKO_DEBUG */ 278232812Sjmallett 279232812Sjmallett/* 280232812Sjmallett * Configure queues for an internal port. 281232812Sjmallett * @INTERNAL 282232812Sjmallett * @param pko_port PKO internal port number 283232812Sjmallett * Note: o68 only 284232812Sjmallett */ 285232812Sjmallettstatic void __cvmx_pko_iport_config(int pko_port) 286232812Sjmallett{ 287232812Sjmallett int queue, base_queue, num_queues; 288232812Sjmallett int static_priority_base; 289232812Sjmallett int static_priority_end; 290232812Sjmallett cvmx_pko_mem_iqueue_ptrs_t config; 291232812Sjmallett uint64_t *buf_ptr = NULL; 292232812Sjmallett uint64_t priorities[CVMX_PKO_NQ_PER_PORT_MAX] = { 293232812Sjmallett [0 ... CVMX_PKO_NQ_PER_PORT_MAX - 1] = 8 }; 294232812Sjmallett 295232812Sjmallett static_priority_base = -1; 296232812Sjmallett static_priority_end = -1; 297232812Sjmallett base_queue = __cvmx_helper_cfg_pko_queue_base(pko_port); 298232812Sjmallett num_queues = __cvmx_helper_cfg_pko_queue_num(pko_port); 299232812Sjmallett 300232812Sjmallett /* 301232812Sjmallett * Give the user a chance to override the per queue priorities. 302232812Sjmallett */ 303232812Sjmallett if (cvmx_override_pko_queue_priority) 304232812Sjmallett cvmx_override_pko_queue_priority(pko_port, &priorities[0]); 305232812Sjmallett 306232812Sjmallett /* 307232812Sjmallett * static queue priority validation 308232812Sjmallett */ 309232812Sjmallett for (queue = 0; queue < num_queues; queue++) 310232812Sjmallett { 311232812Sjmallett if (static_priority_base == -1 && 312232812Sjmallett priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 313232812Sjmallett static_priority_base = queue; 314232812Sjmallett 315232812Sjmallett if (static_priority_base != -1 && 316232812Sjmallett static_priority_end == -1 && 317232812Sjmallett priorities[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && 318232812Sjmallett queue) 319232812Sjmallett static_priority_end = queue - 1; 320232812Sjmallett else if (static_priority_base != -1 && 321232812Sjmallett static_priority_end == -1 && 322232812Sjmallett queue == num_queues - 1) 323232812Sjmallett static_priority_end = queue; /* all queues are static priority */ 324232812Sjmallett 325232812Sjmallett /* 326232812Sjmallett * Check to make sure all static priority queues are contiguous. 327232812Sjmallett * Also catches some cases of static priorites not starting from 328232812Sjmallett * queue 0. 329232812Sjmallett */ 330232812Sjmallett if (static_priority_end != -1 && 331232812Sjmallett (int)queue > static_priority_end && 332232812Sjmallett priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 333232812Sjmallett { 334232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority " 335232812Sjmallett "queues aren't contiguous or don't start at base queue. " 336232812Sjmallett "q: %d, eq: %d\n", (int)queue, static_priority_end); 337232812Sjmallett } 338232812Sjmallett if (static_priority_base > 0) 339232812Sjmallett { 340232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority " 341232812Sjmallett "queues don't start at base queue. sq: %d\n", 342232812Sjmallett static_priority_base); 343232812Sjmallett } 344232812Sjmallett } 345232812Sjmallett 346232812Sjmallett /* 347232812Sjmallett * main loop to set the fields of CVMX_PKO_MEM_IQUEUE_PTRS for 348232812Sjmallett * each queue 349232812Sjmallett */ 350232812Sjmallett for (queue = 0; queue < num_queues; queue++) 351232812Sjmallett { 352232812Sjmallett config.u64 = 0; 353232812Sjmallett config.s.index = queue; 354232812Sjmallett config.s.qid = base_queue + queue; 355232812Sjmallett config.s.ipid = pko_port; 356232812Sjmallett config.s.tail = (queue == (num_queues - 1)); 357232812Sjmallett config.s.s_tail = (queue == static_priority_end); 358232812Sjmallett config.s.static_p = (static_priority_base >= 0); 359232812Sjmallett config.s.static_q = (queue <= static_priority_end); 360232812Sjmallett 361232812Sjmallett /* 362232812Sjmallett * Convert the priority into an enable bit field. 363232812Sjmallett * Try to space the bits out evenly so the packet 364232812Sjmallett * don't get grouped up. 365232812Sjmallett */ 366232812Sjmallett switch ((int)priorities[queue]) 367232812Sjmallett { 368232812Sjmallett case 0: config.s.qos_mask = 0x00; break; 369232812Sjmallett case 1: config.s.qos_mask = 0x01; break; 370232812Sjmallett case 2: config.s.qos_mask = 0x11; break; 371232812Sjmallett case 3: config.s.qos_mask = 0x49; break; 372232812Sjmallett case 4: config.s.qos_mask = 0x55; break; 373232812Sjmallett case 5: config.s.qos_mask = 0x57; break; 374232812Sjmallett case 6: config.s.qos_mask = 0x77; break; 375232812Sjmallett case 7: config.s.qos_mask = 0x7f; break; 376232812Sjmallett case 8: config.s.qos_mask = 0xff; break; 377232812Sjmallett case CVMX_PKO_QUEUE_STATIC_PRIORITY: 378232812Sjmallett config.s.qos_mask = 0xff; 379232812Sjmallett break; 380232812Sjmallett default: 381232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: " 382232812Sjmallett "Invalid priority %llu\n", 383232812Sjmallett (unsigned long long)priorities[queue]); 384232812Sjmallett config.s.qos_mask = 0xff; 385232812Sjmallett break; 386232812Sjmallett } 387232812Sjmallett 388232812Sjmallett /* 389232812Sjmallett * The command queues 390232812Sjmallett */ 391232812Sjmallett { 392232812Sjmallett cvmx_cmd_queue_result_t cmd_res; 393232812Sjmallett 394232812Sjmallett cmd_res = cvmx_cmd_queue_initialize( 395232812Sjmallett CVMX_CMD_QUEUE_PKO(base_queue + queue), 396232812Sjmallett CVMX_PKO_MAX_QUEUE_DEPTH, 397232812Sjmallett CVMX_FPA_OUTPUT_BUFFER_POOL, 398232812Sjmallett (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - 399232812Sjmallett CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); 400232812Sjmallett 401232812Sjmallett if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) 402232812Sjmallett { 403232812Sjmallett switch (cmd_res) 404232812Sjmallett { 405232812Sjmallett case CVMX_CMD_QUEUE_NO_MEMORY: 406232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Unable to allocate output buffer."); 407232812Sjmallett break; 408232812Sjmallett case CVMX_CMD_QUEUE_ALREADY_SETUP: 409232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Port already setup"); 410232812Sjmallett break; 411232812Sjmallett case CVMX_CMD_QUEUE_INVALID_PARAM: 412232812Sjmallett default: 413232812Sjmallett cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Command queue initialization failed."); 414232812Sjmallett break; 415232812Sjmallett } 416232812Sjmallett cvmx_dprintf(" pko_port%d base_queue%d num_queues%d queue%d.\n", 417232812Sjmallett pko_port, base_queue, num_queues, queue); 418232812Sjmallett } 419232812Sjmallett 420232812Sjmallett buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer( 421232812Sjmallett CVMX_CMD_QUEUE_PKO(base_queue + queue)); 422232812Sjmallett config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; 423232812Sjmallett } 424232812Sjmallett 425232812Sjmallett CVMX_SYNCWS; 426232812Sjmallett cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); 427232812Sjmallett } 428232812Sjmallett} 429232812Sjmallett 430232812Sjmallett/* 431232812Sjmallett * Allocate queues for the PKO internal ports. 432232812Sjmallett * @INTERNAL 433232812Sjmallett * 434232812Sjmallett */ 435232812Sjmallettstatic void __cvmx_pko_queue_alloc_o68(void) 436232812Sjmallett{ 437232812Sjmallett CVMX_PKO_FOR_EACH_PORT_BEGIN { 438232812Sjmallett __cvmx_pko_iport_config(XIT_pko_port); 439232812Sjmallett } CVMX_PKO_FOR_EACH_PORT_END; 440232812Sjmallett} 441232812Sjmallett 442232812Sjmallett/* 443232812Sjmallett * Allocate memory for PKO engines. 444232812Sjmallett * 445232812Sjmallett * @param engine is the PKO engine ID. 446232812Sjmallett * @return # of 2KB-chunks allocated to this PKO engine. 447232812Sjmallett */ 448232812Sjmallettstatic int __cvmx_pko_memory_per_engine_o68(int engine) 449232812Sjmallett{ 450232812Sjmallett /* CN68XX has 40KB to devide between the engines in 2KB chunks */ 451232812Sjmallett int max_engine; 452232812Sjmallett int size_per_engine; 453232812Sjmallett int size; 454232812Sjmallett 455232812Sjmallett max_engine = __cvmx_helper_cfg_pko_max_engine(); 456232812Sjmallett size_per_engine = 40 / 2 / max_engine; 457232812Sjmallett 458232812Sjmallett if (engine >= max_engine) 459232812Sjmallett { 460232812Sjmallett /* Unused engines get no space */ 461232812Sjmallett size = 0; 462232812Sjmallett } 463232812Sjmallett else if (engine == max_engine - 1) 464232812Sjmallett { 465232812Sjmallett /* The last engine gets all the space lost by rounding. This means 466232812Sjmallett the ILK gets the most space */ 467232812Sjmallett size = 40 / 2 - engine * size_per_engine; 468232812Sjmallett } 469232812Sjmallett else 470232812Sjmallett { 471232812Sjmallett /* All other engines get the same space */ 472232812Sjmallett size = size_per_engine; 473232812Sjmallett } 474232812Sjmallett 475232812Sjmallett return size; 476232812Sjmallett} 477232812Sjmallett 478232812Sjmallett/* 479232812Sjmallett * Setup one-to-one mapping between PKO iport and eport. 480232812Sjmallett * @INTERNAL 481232812Sjmallett */ 482232812Sjmallettstatic void __cvmx_pko_port_map_o68(void) 483232812Sjmallett{ 484232812Sjmallett int i; 485232812Sjmallett int interface, index; 486232812Sjmallett cvmx_helper_interface_mode_t mode; 487232812Sjmallett cvmx_pko_mem_iport_ptrs_t config; 488232812Sjmallett 489232812Sjmallett /* 490232812Sjmallett * Initialize every iport with the invalid eid. 491232812Sjmallett */ 492232812Sjmallett#define CVMX_O68_PKO_INVALID_EID 31 493232812Sjmallett config.u64 = 0; 494232812Sjmallett config.s.eid = CVMX_O68_PKO_INVALID_EID; 495232812Sjmallett for (i = 0; i < CVMX_HELPER_CFG_MAX_PKO_PORT; i++) 496232812Sjmallett { 497232812Sjmallett config.s.ipid = i; 498232812Sjmallett cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 499232812Sjmallett } 500232812Sjmallett 501232812Sjmallett /* 502232812Sjmallett * Set up PKO_MEM_IPORT_PTRS 503232812Sjmallett */ 504232812Sjmallett CVMX_PKO_FOR_EACH_PORT_BEGIN { 505232812Sjmallett interface = __cvmx_helper_cfg_pko_port_interface(XIT_pko_port); 506232812Sjmallett index = __cvmx_helper_cfg_pko_port_index(XIT_pko_port); 507232812Sjmallett mode = cvmx_helper_interface_get_mode(interface); 508232812Sjmallett 509232812Sjmallett if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) 510232812Sjmallett continue; 511232812Sjmallett 512232812Sjmallett config.s.ipid = XIT_pko_port; 513232812Sjmallett config.s.qos_mask = 0xff; 514232812Sjmallett config.s.crc = __cvmx_helper_get_has_fcs(interface); 515232812Sjmallett config.s.min_pkt = __cvmx_helper_get_pko_padding(interface); 516232812Sjmallett config.s.intr = __cvmx_pko_int(interface, index); 517232812Sjmallett config.s.eid = __cvmx_helper_cfg_pko_port_eid(XIT_pko_port); 518232812Sjmallett config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? index : 519232812Sjmallett XIT_pko_port; 520232812Sjmallett cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 521232812Sjmallett } CVMX_PKO_FOR_EACH_PORT_END; 522232812Sjmallett} 523232812Sjmallett 524232812Sjmallettint __cvmx_pko_get_pipe(int interface, int index) 525232812Sjmallett{ 526232812Sjmallett /* 527232812Sjmallett * the loopback ports do not have pipes 528232812Sjmallett */ 529232812Sjmallett if (cvmx_helper_interface_get_mode(interface) == 530232812Sjmallett CVMX_HELPER_INTERFACE_MODE_LOOP) 531232812Sjmallett return -1; 532232812Sjmallett /* 533232812Sjmallett * We use pko_port as the pipe. See __cvmx_pko_port_map_o68(). 534232812Sjmallett */ 535232812Sjmallett return cvmx_helper_get_pko_port(interface, index); 536232812Sjmallett} 537232812Sjmallett 538232812Sjmallett/* 539232812Sjmallett * chip-specific setup 540232812Sjmallett * @INTERNAL 541232812Sjmallett */ 542232812Sjmallettstatic void __cvmx_pko_chip_init(void) 543232812Sjmallett{ 544232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 545232812Sjmallett { 546232812Sjmallett __cvmx_pko_port_map_o68(); 547232812Sjmallett __cvmx_pko_queue_alloc_o68(); 548232812Sjmallett } 549232812Sjmallett else 550232812Sjmallett { 551232812Sjmallett int i; 552232812Sjmallett uint64_t priority = 8; 553232812Sjmallett 554232812Sjmallett /* 555232812Sjmallett * Initialize queues 556232812Sjmallett */ 557232812Sjmallett for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) 558232812Sjmallett cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, 559232812Sjmallett &priority); 560232812Sjmallett } 561232812Sjmallett} 562232812Sjmallett 563232812Sjmallett/** 564210284Sjmallett * Call before any other calls to initialize the packet 565210284Sjmallett * output system. This does chip global config, and should only be 566210284Sjmallett * done by one core. 567210284Sjmallett */ 568210284Sjmallett 569210284Sjmallettvoid cvmx_pko_initialize_global(void) 570210284Sjmallett{ 571232812Sjmallett cvmx_pko_reg_cmd_buf_t config; 572210284Sjmallett int i; 573210284Sjmallett 574232812Sjmallett /* 575232812Sjmallett * Set the size of the PKO command buffers to an odd number of 64bit 576232812Sjmallett * words. This allows the normal two word send to stay aligned and never 577232812Sjmallett * span a command word buffer. 578232812Sjmallett */ 579210284Sjmallett config.u64 = 0; 580210284Sjmallett config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; 581210284Sjmallett config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; 582210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); 583210284Sjmallett 584232812Sjmallett /* 585232812Sjmallett * chip-specific setup. 586232812Sjmallett */ 587232812Sjmallett __cvmx_pko_chip_init(); 588210284Sjmallett 589232812Sjmallett /* 590232812Sjmallett * If we aren't using all of the queues optimize PKO's internal memory. 591232812Sjmallett */ 592232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || 593232812Sjmallett OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) || 594232812Sjmallett OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX)) 595210284Sjmallett { 596232812Sjmallett int num_interfaces; 597232812Sjmallett int last_port; 598232812Sjmallett int max_queues; 599232812Sjmallett 600232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 601232812Sjmallett max_queues = __cvmx_helper_cfg_pko_max_queue(); 602232812Sjmallett else 603232812Sjmallett { 604232812Sjmallett num_interfaces = cvmx_helper_get_number_of_interfaces(); 605232812Sjmallett last_port = cvmx_helper_get_last_ipd_port(num_interfaces-1); 606232812Sjmallett max_queues = cvmx_pko_get_base_queue(last_port) + 607232812Sjmallett cvmx_pko_get_num_queues(last_port); 608232812Sjmallett } 609232812Sjmallett 610210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 611210284Sjmallett { 612210284Sjmallett if (max_queues <= 32) 613210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 614210284Sjmallett else if (max_queues <= 64) 615210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 616232812Sjmallett else 617232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0); 618210284Sjmallett } 619210284Sjmallett else 620210284Sjmallett { 621232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX) && max_queues <= 32) 622232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 3); 623232812Sjmallett else if (max_queues <= 64) 624210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 625210284Sjmallett else if (max_queues <= 128) 626210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 627232812Sjmallett else 628232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0); 629232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 630232812Sjmallett { 631232812Sjmallett for (i = 0; i < 2; i++) 632232812Sjmallett { 633232812Sjmallett cvmx_pko_reg_engine_storagex_t engine_storage; 634232812Sjmallett 635232812Sjmallett#define PKO_ASSIGN_ENGINE_STORAGE(index) \ 636232812Sjmallett engine_storage.s.engine##index = \ 637232812Sjmallett __cvmx_pko_memory_per_engine_o68(16 * i + (index)) 638232812Sjmallett 639232812Sjmallett engine_storage.u64 = 0; 640232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(0); 641232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(1); 642232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(2); 643232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(3); 644232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(4); 645232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(5); 646232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(6); 647232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(7); 648232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(8); 649232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(9); 650232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(10); 651232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(11); 652232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(12); 653232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(13); 654232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(14); 655232812Sjmallett PKO_ASSIGN_ENGINE_STORAGE(15); 656232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_ENGINE_STORAGEX(i), 657232812Sjmallett engine_storage.u64); 658232812Sjmallett } 659232812Sjmallett } 660210284Sjmallett } 661210284Sjmallett } 662210284Sjmallett} 663210284Sjmallett 664210284Sjmallett/** 665210284Sjmallett * This function does per-core initialization required by the PKO routines. 666210284Sjmallett * This must be called on all cores that will do packet output, and must 667210284Sjmallett * be called after the FPA has been initialized and filled with pages. 668210284Sjmallett * 669210284Sjmallett * @return 0 on success 670210284Sjmallett * !0 on failure 671210284Sjmallett */ 672210284Sjmallettint cvmx_pko_initialize_local(void) 673210284Sjmallett{ 674210284Sjmallett /* Nothing to do */ 675210284Sjmallett return 0; 676210284Sjmallett} 677210284Sjmallett#endif 678210284Sjmallett 679210284Sjmallett/** 680210284Sjmallett * Enables the packet output hardware. It must already be 681210284Sjmallett * configured. 682210284Sjmallett */ 683210284Sjmallettvoid cvmx_pko_enable(void) 684210284Sjmallett{ 685210284Sjmallett cvmx_pko_reg_flags_t flags; 686210284Sjmallett 687210284Sjmallett flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 688210284Sjmallett if (flags.s.ena_pko) 689210284Sjmallett cvmx_dprintf("Warning: Enabling PKO when PKO already enabled.\n"); 690210284Sjmallett 691232812Sjmallett flags.s.ena_dwb = cvmx_helper_cfg_opt_get(CVMX_HELPER_CFG_OPT_USE_DWB); 692210284Sjmallett flags.s.ena_pko = 1; 693232812Sjmallett flags.s.store_be =1; /* 694232812Sjmallett * always enable big endian for 3-word command. 695232812Sjmallett * Does nothing for 2-word. 696232812Sjmallett */ 697210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); 698210284Sjmallett} 699210284Sjmallett 700210284Sjmallett/** 701210284Sjmallett * Disables the packet output. Does not affect any configuration. 702210284Sjmallett */ 703210284Sjmallettvoid cvmx_pko_disable(void) 704210284Sjmallett{ 705210284Sjmallett cvmx_pko_reg_flags_t pko_reg_flags; 706210284Sjmallett pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 707210284Sjmallett pko_reg_flags.s.ena_pko = 0; 708210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 709210284Sjmallett} 710210284Sjmallett 711210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 712210284Sjmallett/** 713210284Sjmallett * @INTERNAL 714210284Sjmallett * Reset the packet output. 715210284Sjmallett */ 716210284Sjmallettstatic void __cvmx_pko_reset(void) 717210284Sjmallett{ 718210284Sjmallett cvmx_pko_reg_flags_t pko_reg_flags; 719210284Sjmallett pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 720210284Sjmallett pko_reg_flags.s.reset = 1; 721210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 722210284Sjmallett} 723210284Sjmallett 724210284Sjmallett/** 725210284Sjmallett * Shutdown and free resources required by packet output. 726210284Sjmallett */ 727210284Sjmallettvoid cvmx_pko_shutdown(void) 728210284Sjmallett{ 729210284Sjmallett int queue; 730210284Sjmallett 731210284Sjmallett cvmx_pko_disable(); 732210284Sjmallett 733232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 734210284Sjmallett { 735232812Sjmallett cvmx_pko_mem_iqueue_ptrs_t config; 736232812Sjmallett config.u64 = 0; 737232812Sjmallett for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) 738232812Sjmallett { 739232812Sjmallett config.s.qid = queue; 740232812Sjmallett cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); 741232812Sjmallett cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 742232812Sjmallett } 743232812Sjmallett } 744232812Sjmallett else 745232812Sjmallett { 746232812Sjmallett cvmx_pko_mem_queue_ptrs_t config; 747232812Sjmallett for (queue=0; queue<CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) 748210284Sjmallett { 749232812Sjmallett config.u64 = 0; 750232812Sjmallett config.s.tail = 1; 751232812Sjmallett config.s.index = 0; 752232812Sjmallett config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; 753232812Sjmallett config.s.queue = queue & 0x7f; 754232812Sjmallett config.s.qos_mask = 0; 755232812Sjmallett config.s.buf_ptr = 0; 756232812Sjmallett if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 757232812Sjmallett { 758232812Sjmallett cvmx_pko_reg_queue_ptrs1_t config1; 759232812Sjmallett config1.u64 = 0; 760232812Sjmallett config1.s.qid7 = queue >> 7; 761232812Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 762232812Sjmallett } 763232812Sjmallett cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 764232812Sjmallett cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 765210284Sjmallett } 766210284Sjmallett } 767232812Sjmallett 768210284Sjmallett __cvmx_pko_reset(); 769210284Sjmallett} 770210284Sjmallett 771210284Sjmallett/** 772210284Sjmallett * Configure a output port and the associated queues for use. 773210284Sjmallett * 774210284Sjmallett * @param port Port to configure. 775210284Sjmallett * @param base_queue First queue number to associate with this port. 776210284Sjmallett * @param num_queues Number of queues to associate with this port 777210284Sjmallett * @param priority Array of priority levels for each queue. Values are 778210284Sjmallett * allowed to be 0-8. A value of 8 get 8 times the traffic 779210284Sjmallett * of a value of 1. A value of 0 indicates that no rounds 780210284Sjmallett * will be participated in. These priorities can be changed 781210284Sjmallett * on the fly while the pko is enabled. A priority of 9 782210284Sjmallett * indicates that static priority should be used. If static 783210284Sjmallett * priority is used all queues with static priority must be 784210284Sjmallett * contiguous starting at the base_queue, and lower numbered 785210284Sjmallett * queues have higher priority than higher numbered queues. 786210284Sjmallett * There must be num_queues elements in the array. 787210284Sjmallett */ 788232812Sjmallettcvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, 789232812Sjmallett uint64_t num_queues, const uint64_t priority[]) 790210284Sjmallett{ 791210284Sjmallett cvmx_pko_status_t result_code; 792210284Sjmallett uint64_t queue; 793215990Sjmallett cvmx_pko_mem_queue_ptrs_t config; 794210284Sjmallett cvmx_pko_reg_queue_ptrs1_t config1; 795210284Sjmallett int static_priority_base = -1; 796210284Sjmallett int static_priority_end = -1; 797210284Sjmallett 798232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 799232812Sjmallett return CVMX_PKO_SUCCESS; 800210284Sjmallett 801232812Sjmallett if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) && 802232812Sjmallett (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) 803210284Sjmallett { 804232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", 805232812Sjmallett (unsigned long long)port); 806210284Sjmallett return CVMX_PKO_INVALID_PORT; 807210284Sjmallett } 808210284Sjmallett 809210284Sjmallett if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) 810210284Sjmallett { 811232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", 812232812Sjmallett (unsigned long long)(base_queue + num_queues)); 813210284Sjmallett return CVMX_PKO_INVALID_QUEUE; 814210284Sjmallett } 815210284Sjmallett 816210284Sjmallett if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 817210284Sjmallett { 818232812Sjmallett /* 819232812Sjmallett * Validate the static queue priority setup and set 820232812Sjmallett * static_priority_base and static_priority_end accordingly. 821232812Sjmallett */ 822210284Sjmallett for (queue = 0; queue < num_queues; queue++) 823210284Sjmallett { 824210284Sjmallett /* Find first queue of static priority */ 825232812Sjmallett if (static_priority_base == -1 && priority[queue] == 826232812Sjmallett CVMX_PKO_QUEUE_STATIC_PRIORITY) 827210284Sjmallett static_priority_base = queue; 828210284Sjmallett /* Find last queue of static priority */ 829232812Sjmallett if (static_priority_base != -1 && static_priority_end == -1 && 830232812Sjmallett priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && queue) 831210284Sjmallett static_priority_end = queue - 1; 832232812Sjmallett else if (static_priority_base != -1 && static_priority_end == -1 && 833232812Sjmallett queue == num_queues - 1) 834232812Sjmallett static_priority_end = queue; /* all queues're static priority */ 835232812Sjmallett 836232812Sjmallett /* 837232812Sjmallett * Check to make sure all static priority queues are contiguous. 838232812Sjmallett * Also catches some cases of static priorites not starting at 839232812Sjmallett * queue 0. 840232812Sjmallett */ 841232812Sjmallett if (static_priority_end != -1 && (int)queue > static_priority_end && 842232812Sjmallett priority[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 843210284Sjmallett { 844232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority " 845232812Sjmallett "queues aren't contiguous or don't start at base queue. " 846232812Sjmallett "q: %d, eq: %d\n", (int)queue, static_priority_end); 847210284Sjmallett return CVMX_PKO_INVALID_PRIORITY; 848210284Sjmallett } 849210284Sjmallett } 850210284Sjmallett if (static_priority_base > 0) 851210284Sjmallett { 852232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority queues " 853232812Sjmallett "don't start at base queue. sq: %d\n", static_priority_base); 854210284Sjmallett return CVMX_PKO_INVALID_PRIORITY; 855210284Sjmallett } 856210284Sjmallett } 857210284Sjmallett 858232812Sjmallett /* 859232812Sjmallett * At this point, static_priority_base and static_priority_end are either 860232812Sjmallett * both -1, or are valid start/end queue numbers 861232812Sjmallett */ 862232812Sjmallett 863210284Sjmallett result_code = CVMX_PKO_SUCCESS; 864210284Sjmallett 865210284Sjmallett#ifdef PKO_DEBUG 866232812Sjmallett cvmx_dprintf("num queues: %d (%lld,%lld)\n", (int)num_queues, 867232812Sjmallett (unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, 868232812Sjmallett (unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); 869210284Sjmallett#endif 870210284Sjmallett 871210284Sjmallett for (queue = 0; queue < num_queues; queue++) 872210284Sjmallett { 873210284Sjmallett uint64_t *buf_ptr = NULL; 874210284Sjmallett 875210284Sjmallett config1.u64 = 0; 876210284Sjmallett config1.s.idx3 = queue >> 3; 877210284Sjmallett config1.s.qid7 = (base_queue + queue) >> 7; 878210284Sjmallett 879210284Sjmallett config.u64 = 0; 880210284Sjmallett config.s.tail = queue == (num_queues - 1); 881210284Sjmallett config.s.index = queue; 882210284Sjmallett config.s.port = port; 883210284Sjmallett config.s.queue = base_queue + queue; 884210284Sjmallett 885215990Sjmallett config.s.static_p = static_priority_base >= 0; 886215990Sjmallett config.s.static_q = (int)queue <= static_priority_end; 887215990Sjmallett config.s.s_tail = (int)queue == static_priority_end; 888232812Sjmallett /* 889232812Sjmallett * Convert the priority into an enable bit field. Try to space the bits 890232812Sjmallett * out evenly so the packet don't get grouped up 891232812Sjmallett */ 892210284Sjmallett switch ((int)priority[queue]) 893210284Sjmallett { 894210284Sjmallett case 0: config.s.qos_mask = 0x00; break; 895210284Sjmallett case 1: config.s.qos_mask = 0x01; break; 896210284Sjmallett case 2: config.s.qos_mask = 0x11; break; 897210284Sjmallett case 3: config.s.qos_mask = 0x49; break; 898210284Sjmallett case 4: config.s.qos_mask = 0x55; break; 899210284Sjmallett case 5: config.s.qos_mask = 0x57; break; 900210284Sjmallett case 6: config.s.qos_mask = 0x77; break; 901210284Sjmallett case 7: config.s.qos_mask = 0x7f; break; 902210284Sjmallett case 8: config.s.qos_mask = 0xff; break; 903210284Sjmallett case CVMX_PKO_QUEUE_STATIC_PRIORITY: 904215990Sjmallett config.s.qos_mask = 0xff; 905215990Sjmallett break; 906210284Sjmallett default: 907232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid priority %llu\n", 908232812Sjmallett (unsigned long long)priority[queue]); 909210284Sjmallett config.s.qos_mask = 0xff; 910210284Sjmallett result_code = CVMX_PKO_INVALID_PRIORITY; 911210284Sjmallett break; 912210284Sjmallett } 913210284Sjmallett 914210284Sjmallett if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 915210284Sjmallett { 916232812Sjmallett cvmx_cmd_queue_result_t cmd_res = cvmx_cmd_queue_initialize( 917232812Sjmallett CVMX_CMD_QUEUE_PKO(base_queue + queue), 918232812Sjmallett CVMX_PKO_MAX_QUEUE_DEPTH, 919232812Sjmallett CVMX_FPA_OUTPUT_BUFFER_POOL, 920232812Sjmallett CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - 921232812Sjmallett CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST*8); 922210284Sjmallett if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) 923210284Sjmallett { 924215990Sjmallett switch (cmd_res) 925210284Sjmallett { 926210284Sjmallett case CVMX_CMD_QUEUE_NO_MEMORY: 927232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: " 928232812Sjmallett "Unable to allocate output buffer.\n"); 929210284Sjmallett return(CVMX_PKO_NO_MEMORY); 930210284Sjmallett case CVMX_CMD_QUEUE_ALREADY_SETUP: 931232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: " 932232812Sjmallett "Port already setup.\n"); 933210284Sjmallett return(CVMX_PKO_PORT_ALREADY_SETUP); 934210284Sjmallett case CVMX_CMD_QUEUE_INVALID_PARAM: 935210284Sjmallett default: 936232812Sjmallett cvmx_dprintf("ERROR: cvmx_pko_config_port: " 937232812Sjmallett "Command queue initialization failed.\n"); 938210284Sjmallett return(CVMX_PKO_CMD_QUEUE_INIT_ERROR); 939210284Sjmallett } 940210284Sjmallett } 941210284Sjmallett 942232812Sjmallett buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer( 943232812Sjmallett CVMX_CMD_QUEUE_PKO(base_queue + queue)); 944210284Sjmallett config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); 945210284Sjmallett } 946210284Sjmallett else 947210284Sjmallett config.s.buf_ptr = 0; 948210284Sjmallett 949210284Sjmallett CVMX_SYNCWS; 950210284Sjmallett 951210284Sjmallett if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 952210284Sjmallett { 953210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 954210284Sjmallett } 955210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 956210284Sjmallett } 957210284Sjmallett 958210284Sjmallett return result_code; 959210284Sjmallett} 960210284Sjmallett 961210284Sjmallett/** 962210284Sjmallett * Rate limit a PKO port to a max packets/sec. This function is only 963210284Sjmallett * supported on CN51XX and higher, excluding CN58XX. 964210284Sjmallett * 965210284Sjmallett * @param port Port to rate limit 966210284Sjmallett * @param packets_s Maximum packet/sec 967210284Sjmallett * @param burst Maximum number of packets to burst in a row before rate 968210284Sjmallett * limiting cuts in. 969210284Sjmallett * 970210284Sjmallett * @return Zero on success, negative on failure 971210284Sjmallett */ 972210284Sjmallettint cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) 973210284Sjmallett{ 974210284Sjmallett cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 975210284Sjmallett cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 976210284Sjmallett 977210284Sjmallett pko_mem_port_rate0.u64 = 0; 978210284Sjmallett pko_mem_port_rate0.s.pid = port; 979232812Sjmallett pko_mem_port_rate0.s.rate_pkt = 980232812Sjmallett cvmx_clock_get_rate(CVMX_CLOCK_SCLK) / packets_s / 16; 981210284Sjmallett /* No cost per word since we are limited by packets/sec, not bits/sec */ 982210284Sjmallett pko_mem_port_rate0.s.rate_word = 0; 983210284Sjmallett 984210284Sjmallett pko_mem_port_rate1.u64 = 0; 985210284Sjmallett pko_mem_port_rate1.s.pid = port; 986232812Sjmallett pko_mem_port_rate1.s.rate_lim = 987232812Sjmallett ((uint64_t)pko_mem_port_rate0.s.rate_pkt * burst) >> 8; 988210284Sjmallett 989210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 990210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 991210284Sjmallett return 0; 992210284Sjmallett} 993210284Sjmallett 994210284Sjmallett/** 995210284Sjmallett * Rate limit a PKO port to a max bits/sec. This function is only 996210284Sjmallett * supported on CN51XX and higher, excluding CN58XX. 997210284Sjmallett * 998210284Sjmallett * @param port Port to rate limit 999210284Sjmallett * @param bits_s PKO rate limit in bits/sec 1000210284Sjmallett * @param burst Maximum number of bits to burst before rate 1001210284Sjmallett * limiting cuts in. 1002210284Sjmallett * 1003210284Sjmallett * @return Zero on success, negative on failure 1004210284Sjmallett */ 1005210284Sjmallettint cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) 1006210284Sjmallett{ 1007210284Sjmallett cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 1008210284Sjmallett cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 1009215990Sjmallett uint64_t clock_rate = cvmx_clock_get_rate(CVMX_CLOCK_SCLK); 1010210284Sjmallett uint64_t tokens_per_bit = clock_rate*16 / bits_s; 1011210284Sjmallett 1012210284Sjmallett pko_mem_port_rate0.u64 = 0; 1013210284Sjmallett pko_mem_port_rate0.s.pid = port; 1014210284Sjmallett /* Each packet has a 12 bytes of interframe gap, an 8 byte preamble, and a 1015210284Sjmallett 4 byte CRC. These are not included in the per word count. Multiply 1016210284Sjmallett by 8 to covert to bits and divide by 256 for limit granularity */ 1017210284Sjmallett pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; 1018210284Sjmallett /* Each 8 byte word has 64bits */ 1019210284Sjmallett pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; 1020210284Sjmallett 1021210284Sjmallett pko_mem_port_rate1.u64 = 0; 1022210284Sjmallett pko_mem_port_rate1.s.pid = port; 1023210284Sjmallett pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; 1024210284Sjmallett 1025210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 1026210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 1027210284Sjmallett return 0; 1028210284Sjmallett} 1029210284Sjmallett 1030210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 1031