162306a36Sopenharmony_ci/***********************license start*************** 262306a36Sopenharmony_ci * Author: Cavium Networks 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Contact: support@caviumnetworks.com 562306a36Sopenharmony_ci * This file is part of the OCTEON SDK 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2003-2008 Cavium Networks 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 1162306a36Sopenharmony_ci * published by the Free Software Foundation. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 1462306a36Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 1562306a36Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 1662306a36Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more 1762306a36Sopenharmony_ci * details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 2062306a36Sopenharmony_ci * along with this file; if not, write to the Free Software 2162306a36Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2262306a36Sopenharmony_ci * or visit http://www.gnu.org/licenses/. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * This file may also be available under a different license from Cavium. 2562306a36Sopenharmony_ci * Contact Cavium Networks for more information 2662306a36Sopenharmony_ci ***********************license end**************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Support library for the hardware Packet Output unit. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/octeon/octeon.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <asm/octeon/cvmx-config.h> 3562306a36Sopenharmony_ci#include <asm/octeon/cvmx-pko.h> 3662306a36Sopenharmony_ci#include <asm/octeon/cvmx-helper.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Internal state of packet output 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int __cvmx_pko_int(int interface, int index) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci switch (interface) { 4562306a36Sopenharmony_ci case 0: 4662306a36Sopenharmony_ci return index; 4762306a36Sopenharmony_ci case 1: 4862306a36Sopenharmony_ci return 4; 4962306a36Sopenharmony_ci case 2: 5062306a36Sopenharmony_ci return index + 0x08; 5162306a36Sopenharmony_ci case 3: 5262306a36Sopenharmony_ci return index + 0x0c; 5362306a36Sopenharmony_ci case 4: 5462306a36Sopenharmony_ci return index + 0x10; 5562306a36Sopenharmony_ci case 5: 5662306a36Sopenharmony_ci return 0x1c; 5762306a36Sopenharmony_ci case 6: 5862306a36Sopenharmony_ci return 0x1d; 5962306a36Sopenharmony_ci case 7: 6062306a36Sopenharmony_ci return 0x1e; 6162306a36Sopenharmony_ci case 8: 6262306a36Sopenharmony_ci return 0x1f; 6362306a36Sopenharmony_ci default: 6462306a36Sopenharmony_ci return -1; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void __cvmx_pko_iport_config(int pko_port) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int queue; 7162306a36Sopenharmony_ci const int num_queues = 1; 7262306a36Sopenharmony_ci const int base_queue = pko_port; 7362306a36Sopenharmony_ci const int static_priority_end = 1; 7462306a36Sopenharmony_ci const int static_priority_base = 1; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (queue = 0; queue < num_queues; queue++) { 7762306a36Sopenharmony_ci union cvmx_pko_mem_iqueue_ptrs config; 7862306a36Sopenharmony_ci cvmx_cmd_queue_result_t cmd_res; 7962306a36Sopenharmony_ci uint64_t *buf_ptr; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci config.u64 = 0; 8262306a36Sopenharmony_ci config.s.index = queue; 8362306a36Sopenharmony_ci config.s.qid = base_queue + queue; 8462306a36Sopenharmony_ci config.s.ipid = pko_port; 8562306a36Sopenharmony_ci config.s.tail = (queue == (num_queues - 1)); 8662306a36Sopenharmony_ci config.s.s_tail = (queue == static_priority_end); 8762306a36Sopenharmony_ci config.s.static_p = (static_priority_base >= 0); 8862306a36Sopenharmony_ci config.s.static_q = (queue <= static_priority_end); 8962306a36Sopenharmony_ci config.s.qos_mask = 0xff; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci cmd_res = cvmx_cmd_queue_initialize( 9262306a36Sopenharmony_ci CVMX_CMD_QUEUE_PKO(base_queue + queue), 9362306a36Sopenharmony_ci CVMX_PKO_MAX_QUEUE_DEPTH, 9462306a36Sopenharmony_ci CVMX_FPA_OUTPUT_BUFFER_POOL, 9562306a36Sopenharmony_ci (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - 9662306a36Sopenharmony_ci CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci WARN(cmd_res, 9962306a36Sopenharmony_ci "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n", 10062306a36Sopenharmony_ci __func__, (int)cmd_res, pko_port, base_queue, 10162306a36Sopenharmony_ci num_queues, queue); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer( 10462306a36Sopenharmony_ci CVMX_CMD_QUEUE_PKO(base_queue + queue)); 10562306a36Sopenharmony_ci config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; 10662306a36Sopenharmony_ci CVMX_SYNCWS; 10762306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void __cvmx_pko_queue_alloc_o68(void) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int port; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci for (port = 0; port < 48; port++) 11662306a36Sopenharmony_ci __cvmx_pko_iport_config(port); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void __cvmx_pko_port_map_o68(void) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci int port; 12262306a36Sopenharmony_ci int interface, index; 12362306a36Sopenharmony_ci cvmx_helper_interface_mode_t mode; 12462306a36Sopenharmony_ci union cvmx_pko_mem_iport_ptrs config; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Initialize every iport with the invalid eid. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci config.u64 = 0; 13062306a36Sopenharmony_ci config.s.eid = 31; /* Invalid */ 13162306a36Sopenharmony_ci for (port = 0; port < 128; port++) { 13262306a36Sopenharmony_ci config.s.ipid = port; 13362306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Set up PKO_MEM_IPORT_PTRS 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci for (port = 0; port < 48; port++) { 14062306a36Sopenharmony_ci interface = cvmx_helper_get_interface_num(port); 14162306a36Sopenharmony_ci index = cvmx_helper_get_interface_index_num(port); 14262306a36Sopenharmony_ci mode = cvmx_helper_interface_get_mode(interface); 14362306a36Sopenharmony_ci if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) 14462306a36Sopenharmony_ci continue; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci config.s.ipid = port; 14762306a36Sopenharmony_ci config.s.qos_mask = 0xff; 14862306a36Sopenharmony_ci config.s.crc = 1; 14962306a36Sopenharmony_ci config.s.min_pkt = 1; 15062306a36Sopenharmony_ci config.s.intr = __cvmx_pko_int(interface, index); 15162306a36Sopenharmony_ci config.s.eid = config.s.intr; 15262306a36Sopenharmony_ci config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? 15362306a36Sopenharmony_ci index : port; 15462306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void __cvmx_pko_chip_init(void) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int i; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { 16362306a36Sopenharmony_ci __cvmx_pko_port_map_o68(); 16462306a36Sopenharmony_ci __cvmx_pko_queue_alloc_o68(); 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * Initialize queues 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) { 17262306a36Sopenharmony_ci const uint64_t priority = 8; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, 17562306a36Sopenharmony_ci &priority); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Call before any other calls to initialize the packet 18162306a36Sopenharmony_ci * output system. This does chip global config, and should only be 18262306a36Sopenharmony_ci * done by one core. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid cvmx_pko_initialize_global(void) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci union cvmx_pko_reg_cmd_buf config; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Set the size of the PKO command buffers to an odd number of 19162306a36Sopenharmony_ci * 64bit words. This allows the normal two word send to stay 19262306a36Sopenharmony_ci * aligned and never span a command word buffer. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci config.u64 = 0; 19562306a36Sopenharmony_ci config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; 19662306a36Sopenharmony_ci config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * Chip-specific setup. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci __cvmx_pko_chip_init(); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* 20662306a36Sopenharmony_ci * If we aren't using all of the queues optimize PKO's 20762306a36Sopenharmony_ci * internal memory. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) 21062306a36Sopenharmony_ci || OCTEON_IS_MODEL(OCTEON_CN56XX) 21162306a36Sopenharmony_ci || OCTEON_IS_MODEL(OCTEON_CN52XX)) { 21262306a36Sopenharmony_ci int num_interfaces = cvmx_helper_get_number_of_interfaces(); 21362306a36Sopenharmony_ci int last_port = 21462306a36Sopenharmony_ci cvmx_helper_get_last_ipd_port(num_interfaces - 1); 21562306a36Sopenharmony_ci int max_queues = 21662306a36Sopenharmony_ci cvmx_pko_get_base_queue(last_port) + 21762306a36Sopenharmony_ci cvmx_pko_get_num_queues(last_port); 21862306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { 21962306a36Sopenharmony_ci if (max_queues <= 32) 22062306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 22162306a36Sopenharmony_ci else if (max_queues <= 64) 22262306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 22362306a36Sopenharmony_ci } else { 22462306a36Sopenharmony_ci if (max_queues <= 64) 22562306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 22662306a36Sopenharmony_ci else if (max_queues <= 128) 22762306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* 23362306a36Sopenharmony_ci * Enables the packet output hardware. It must already be 23462306a36Sopenharmony_ci * configured. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_civoid cvmx_pko_enable(void) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci union cvmx_pko_reg_flags flags; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 24162306a36Sopenharmony_ci if (flags.s.ena_pko) 24262306a36Sopenharmony_ci cvmx_dprintf 24362306a36Sopenharmony_ci ("Warning: Enabling PKO when PKO already enabled.\n"); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci flags.s.ena_dwb = 1; 24662306a36Sopenharmony_ci flags.s.ena_pko = 1; 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * always enable big endian for 3-word command. Does nothing 24962306a36Sopenharmony_ci * for 2-word. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci flags.s.store_be = 1; 25262306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Disables the packet output. Does not affect any configuration. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_civoid cvmx_pko_disable(void) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci union cvmx_pko_reg_flags pko_reg_flags; 26162306a36Sopenharmony_ci pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 26262306a36Sopenharmony_ci pko_reg_flags.s.ena_pko = 0; 26362306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cvmx_pko_disable); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* 26862306a36Sopenharmony_ci * Reset the packet output. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic void __cvmx_pko_reset(void) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci union cvmx_pko_reg_flags pko_reg_flags; 27362306a36Sopenharmony_ci pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 27462306a36Sopenharmony_ci pko_reg_flags.s.reset = 1; 27562306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * Shutdown and free resources required by packet output. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_civoid cvmx_pko_shutdown(void) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci union cvmx_pko_mem_queue_ptrs config; 28462306a36Sopenharmony_ci int queue; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci cvmx_pko_disable(); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) { 28962306a36Sopenharmony_ci config.u64 = 0; 29062306a36Sopenharmony_ci config.s.tail = 1; 29162306a36Sopenharmony_ci config.s.index = 0; 29262306a36Sopenharmony_ci config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; 29362306a36Sopenharmony_ci config.s.queue = queue & 0x7f; 29462306a36Sopenharmony_ci config.s.qos_mask = 0; 29562306a36Sopenharmony_ci config.s.buf_ptr = 0; 29662306a36Sopenharmony_ci if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) { 29762306a36Sopenharmony_ci union cvmx_pko_reg_queue_ptrs1 config1; 29862306a36Sopenharmony_ci config1.u64 = 0; 29962306a36Sopenharmony_ci config1.s.qid7 = queue >> 7; 30062306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 30362306a36Sopenharmony_ci cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci __cvmx_pko_reset(); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cvmx_pko_shutdown); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* 31062306a36Sopenharmony_ci * Configure a output port and the associated queues for use. 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * @port: Port to configure. 31362306a36Sopenharmony_ci * @base_queue: First queue number to associate with this port. 31462306a36Sopenharmony_ci * @num_queues: Number of queues to associate with this port 31562306a36Sopenharmony_ci * @priority: Array of priority levels for each queue. Values are 31662306a36Sopenharmony_ci * allowed to be 0-8. A value of 8 get 8 times the traffic 31762306a36Sopenharmony_ci * of a value of 1. A value of 0 indicates that no rounds 31862306a36Sopenharmony_ci * will be participated in. These priorities can be changed 31962306a36Sopenharmony_ci * on the fly while the pko is enabled. A priority of 9 32062306a36Sopenharmony_ci * indicates that static priority should be used. If static 32162306a36Sopenharmony_ci * priority is used all queues with static priority must be 32262306a36Sopenharmony_ci * contiguous starting at the base_queue, and lower numbered 32362306a36Sopenharmony_ci * queues have higher priority than higher numbered queues. 32462306a36Sopenharmony_ci * There must be num_queues elements in the array. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cicvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, 32762306a36Sopenharmony_ci uint64_t num_queues, 32862306a36Sopenharmony_ci const uint64_t priority[]) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci cvmx_pko_status_t result_code; 33162306a36Sopenharmony_ci uint64_t queue; 33262306a36Sopenharmony_ci union cvmx_pko_mem_queue_ptrs config; 33362306a36Sopenharmony_ci union cvmx_pko_reg_queue_ptrs1 config1; 33462306a36Sopenharmony_ci int static_priority_base = -1; 33562306a36Sopenharmony_ci int static_priority_end = -1; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN68XX)) 33862306a36Sopenharmony_ci return CVMX_PKO_SUCCESS; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) 34162306a36Sopenharmony_ci && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { 34262306a36Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", 34362306a36Sopenharmony_ci (unsigned long long)port); 34462306a36Sopenharmony_ci return CVMX_PKO_INVALID_PORT; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) { 34862306a36Sopenharmony_ci cvmx_dprintf 34962306a36Sopenharmony_ci ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", 35062306a36Sopenharmony_ci (unsigned long long)(base_queue + num_queues)); 35162306a36Sopenharmony_ci return CVMX_PKO_INVALID_QUEUE; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * Validate the static queue priority setup and set 35762306a36Sopenharmony_ci * static_priority_base and static_priority_end 35862306a36Sopenharmony_ci * accordingly. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci for (queue = 0; queue < num_queues; queue++) { 36162306a36Sopenharmony_ci /* Find first queue of static priority */ 36262306a36Sopenharmony_ci if (static_priority_base == -1 36362306a36Sopenharmony_ci && priority[queue] == 36462306a36Sopenharmony_ci CVMX_PKO_QUEUE_STATIC_PRIORITY) 36562306a36Sopenharmony_ci static_priority_base = queue; 36662306a36Sopenharmony_ci /* Find last queue of static priority */ 36762306a36Sopenharmony_ci if (static_priority_base != -1 36862306a36Sopenharmony_ci && static_priority_end == -1 36962306a36Sopenharmony_ci && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY 37062306a36Sopenharmony_ci && queue) 37162306a36Sopenharmony_ci static_priority_end = queue - 1; 37262306a36Sopenharmony_ci else if (static_priority_base != -1 37362306a36Sopenharmony_ci && static_priority_end == -1 37462306a36Sopenharmony_ci && queue == num_queues - 1) 37562306a36Sopenharmony_ci /* all queues are static priority */ 37662306a36Sopenharmony_ci static_priority_end = queue; 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * Check to make sure all static priority 37962306a36Sopenharmony_ci * queues are contiguous. Also catches some 38062306a36Sopenharmony_ci * cases of static priorities not starting at 38162306a36Sopenharmony_ci * queue 0. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (static_priority_end != -1 38462306a36Sopenharmony_ci && (int)queue > static_priority_end 38562306a36Sopenharmony_ci && priority[queue] == 38662306a36Sopenharmony_ci CVMX_PKO_QUEUE_STATIC_PRIORITY) { 38762306a36Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_pko_config_port: " 38862306a36Sopenharmony_ci "Static priority queues aren't " 38962306a36Sopenharmony_ci "contiguous or don't start at " 39062306a36Sopenharmony_ci "base queue. q: %d, eq: %d\n", 39162306a36Sopenharmony_ci (int)queue, static_priority_end); 39262306a36Sopenharmony_ci return CVMX_PKO_INVALID_PRIORITY; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci if (static_priority_base > 0) { 39662306a36Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_pko_config_port: Static " 39762306a36Sopenharmony_ci "priority queues don't start at base " 39862306a36Sopenharmony_ci "queue. sq: %d\n", 39962306a36Sopenharmony_ci static_priority_base); 40062306a36Sopenharmony_ci return CVMX_PKO_INVALID_PRIORITY; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci#if 0 40362306a36Sopenharmony_ci cvmx_dprintf("Port %d: Static priority queue base: %d, " 40462306a36Sopenharmony_ci "end: %d\n", port, 40562306a36Sopenharmony_ci static_priority_base, static_priority_end); 40662306a36Sopenharmony_ci#endif 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci /* 40962306a36Sopenharmony_ci * At this point, static_priority_base and static_priority_end 41062306a36Sopenharmony_ci * are either both -1, or are valid start/end queue 41162306a36Sopenharmony_ci * numbers. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci result_code = CVMX_PKO_SUCCESS; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci#ifdef PKO_DEBUG 41762306a36Sopenharmony_ci cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues, 41862306a36Sopenharmony_ci CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, 41962306a36Sopenharmony_ci CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); 42062306a36Sopenharmony_ci#endif 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci for (queue = 0; queue < num_queues; queue++) { 42362306a36Sopenharmony_ci uint64_t *buf_ptr = NULL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci config1.u64 = 0; 42662306a36Sopenharmony_ci config1.s.idx3 = queue >> 3; 42762306a36Sopenharmony_ci config1.s.qid7 = (base_queue + queue) >> 7; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci config.u64 = 0; 43062306a36Sopenharmony_ci config.s.tail = queue == (num_queues - 1); 43162306a36Sopenharmony_ci config.s.index = queue; 43262306a36Sopenharmony_ci config.s.port = port; 43362306a36Sopenharmony_ci config.s.queue = base_queue + queue; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (!cvmx_octeon_is_pass1()) { 43662306a36Sopenharmony_ci config.s.static_p = static_priority_base >= 0; 43762306a36Sopenharmony_ci config.s.static_q = (int)queue <= static_priority_end; 43862306a36Sopenharmony_ci config.s.s_tail = (int)queue == static_priority_end; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci /* 44162306a36Sopenharmony_ci * Convert the priority into an enable bit field. Try 44262306a36Sopenharmony_ci * to space the bits out evenly so the packet don't 44362306a36Sopenharmony_ci * get grouped up 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci switch ((int)priority[queue]) { 44662306a36Sopenharmony_ci case 0: 44762306a36Sopenharmony_ci config.s.qos_mask = 0x00; 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case 1: 45062306a36Sopenharmony_ci config.s.qos_mask = 0x01; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case 2: 45362306a36Sopenharmony_ci config.s.qos_mask = 0x11; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci case 3: 45662306a36Sopenharmony_ci config.s.qos_mask = 0x49; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case 4: 45962306a36Sopenharmony_ci config.s.qos_mask = 0x55; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case 5: 46262306a36Sopenharmony_ci config.s.qos_mask = 0x57; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case 6: 46562306a36Sopenharmony_ci config.s.qos_mask = 0x77; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case 7: 46862306a36Sopenharmony_ci config.s.qos_mask = 0x7f; 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci case 8: 47162306a36Sopenharmony_ci config.s.qos_mask = 0xff; 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci case CVMX_PKO_QUEUE_STATIC_PRIORITY: 47462306a36Sopenharmony_ci if (!cvmx_octeon_is_pass1()) { 47562306a36Sopenharmony_ci config.s.qos_mask = 0xff; 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci fallthrough; /* to the error case, when Pass 1 */ 47962306a36Sopenharmony_ci default: 48062306a36Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid " 48162306a36Sopenharmony_ci "priority %llu\n", 48262306a36Sopenharmony_ci (unsigned long long)priority[queue]); 48362306a36Sopenharmony_ci config.s.qos_mask = 0xff; 48462306a36Sopenharmony_ci result_code = CVMX_PKO_INVALID_PRIORITY; 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { 48962306a36Sopenharmony_ci cvmx_cmd_queue_result_t cmd_res = 49062306a36Sopenharmony_ci cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO 49162306a36Sopenharmony_ci (base_queue + queue), 49262306a36Sopenharmony_ci CVMX_PKO_MAX_QUEUE_DEPTH, 49362306a36Sopenharmony_ci CVMX_FPA_OUTPUT_BUFFER_POOL, 49462306a36Sopenharmony_ci CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 49562306a36Sopenharmony_ci - 49662306a36Sopenharmony_ci CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST 49762306a36Sopenharmony_ci * 8); 49862306a36Sopenharmony_ci if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) { 49962306a36Sopenharmony_ci switch (cmd_res) { 50062306a36Sopenharmony_ci case CVMX_CMD_QUEUE_NO_MEMORY: 50162306a36Sopenharmony_ci cvmx_dprintf("ERROR: " 50262306a36Sopenharmony_ci "cvmx_pko_config_port: " 50362306a36Sopenharmony_ci "Unable to allocate " 50462306a36Sopenharmony_ci "output buffer.\n"); 50562306a36Sopenharmony_ci return CVMX_PKO_NO_MEMORY; 50662306a36Sopenharmony_ci case CVMX_CMD_QUEUE_ALREADY_SETUP: 50762306a36Sopenharmony_ci cvmx_dprintf 50862306a36Sopenharmony_ci ("ERROR: cvmx_pko_config_port: Port already setup.\n"); 50962306a36Sopenharmony_ci return CVMX_PKO_PORT_ALREADY_SETUP; 51062306a36Sopenharmony_ci case CVMX_CMD_QUEUE_INVALID_PARAM: 51162306a36Sopenharmony_ci default: 51262306a36Sopenharmony_ci cvmx_dprintf 51362306a36Sopenharmony_ci ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n"); 51462306a36Sopenharmony_ci return CVMX_PKO_CMD_QUEUE_INIT_ERROR; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci buf_ptr = 51962306a36Sopenharmony_ci (uint64_t *) 52062306a36Sopenharmony_ci cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO 52162306a36Sopenharmony_ci (base_queue + queue)); 52262306a36Sopenharmony_ci config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); 52362306a36Sopenharmony_ci } else 52462306a36Sopenharmony_ci config.s.buf_ptr = 0; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci CVMX_SYNCWS; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 52962306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 53062306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return result_code; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci#ifdef PKO_DEBUG 53762306a36Sopenharmony_ci/* 53862306a36Sopenharmony_ci * Show map of ports -> queues for different cores. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_civoid cvmx_pko_show_queue_map() 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci int core, port; 54362306a36Sopenharmony_ci int pko_output_ports = 36; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci cvmx_dprintf("port"); 54662306a36Sopenharmony_ci for (port = 0; port < pko_output_ports; port++) 54762306a36Sopenharmony_ci cvmx_dprintf("%3d ", port); 54862306a36Sopenharmony_ci cvmx_dprintf("\n"); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci for (core = 0; core < CVMX_MAX_CORES; core++) { 55162306a36Sopenharmony_ci cvmx_dprintf("\n%2d: ", core); 55262306a36Sopenharmony_ci for (port = 0; port < pko_output_ports; port++) { 55362306a36Sopenharmony_ci cvmx_dprintf("%3d ", 55462306a36Sopenharmony_ci cvmx_pko_get_base_queue_per_core(port, 55562306a36Sopenharmony_ci core)); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci cvmx_dprintf("\n"); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci#endif 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/* 56362306a36Sopenharmony_ci * Rate limit a PKO port to a max packets/sec. This function is only 56462306a36Sopenharmony_ci * supported on CN51XX and higher, excluding CN58XX. 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * @port: Port to rate limit 56762306a36Sopenharmony_ci * @packets_s: Maximum packet/sec 56862306a36Sopenharmony_ci * @burst: Maximum number of packets to burst in a row before rate 56962306a36Sopenharmony_ci * limiting cuts in. 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Returns Zero on success, negative on failure 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ciint cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; 57662306a36Sopenharmony_ci union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci pko_mem_port_rate0.u64 = 0; 57962306a36Sopenharmony_ci pko_mem_port_rate0.s.pid = port; 58062306a36Sopenharmony_ci pko_mem_port_rate0.s.rate_pkt = 58162306a36Sopenharmony_ci cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16; 58262306a36Sopenharmony_ci /* No cost per word since we are limited by packets/sec, not bits/sec */ 58362306a36Sopenharmony_ci pko_mem_port_rate0.s.rate_word = 0; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci pko_mem_port_rate1.u64 = 0; 58662306a36Sopenharmony_ci pko_mem_port_rate1.s.pid = port; 58762306a36Sopenharmony_ci pko_mem_port_rate1.s.rate_lim = 58862306a36Sopenharmony_ci ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 59162306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* 59662306a36Sopenharmony_ci * Rate limit a PKO port to a max bits/sec. This function is only 59762306a36Sopenharmony_ci * supported on CN51XX and higher, excluding CN58XX. 59862306a36Sopenharmony_ci * 59962306a36Sopenharmony_ci * @port: Port to rate limit 60062306a36Sopenharmony_ci * @bits_s: PKO rate limit in bits/sec 60162306a36Sopenharmony_ci * @burst: Maximum number of bits to burst before rate 60262306a36Sopenharmony_ci * limiting cuts in. 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * Returns Zero on success, negative on failure 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ciint cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; 60962306a36Sopenharmony_ci union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; 61062306a36Sopenharmony_ci uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz; 61162306a36Sopenharmony_ci uint64_t tokens_per_bit = clock_rate * 16 / bits_s; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci pko_mem_port_rate0.u64 = 0; 61462306a36Sopenharmony_ci pko_mem_port_rate0.s.pid = port; 61562306a36Sopenharmony_ci /* 61662306a36Sopenharmony_ci * Each packet has a 12 bytes of interframe gap, an 8 byte 61762306a36Sopenharmony_ci * preamble, and a 4 byte CRC. These are not included in the 61862306a36Sopenharmony_ci * per word count. Multiply by 8 to covert to bits and divide 61962306a36Sopenharmony_ci * by 256 for limit granularity. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; 62262306a36Sopenharmony_ci /* Each 8 byte word has 64bits */ 62362306a36Sopenharmony_ci pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci pko_mem_port_rate1.u64 = 0; 62662306a36Sopenharmony_ci pko_mem_port_rate1.s.pid = port; 62762306a36Sopenharmony_ci pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 63062306a36Sopenharmony_ci cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci} 633