cvmx-pko.c revision 210284
1/***********************license start*************** 2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * * Neither the name of Cavium Networks nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 * 23 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33 * 34 * 35 * For any questions regarding licensing please contact marketing@caviumnetworks.com 36 * 37 ***********************license end**************************************/ 38 39 40 41 42 43 44/** 45 * @file 46 * 47 * Support library for the hardware Packet Output unit. 48 * 49 * <hr>$Revision: 42150 $<hr> 50 */ 51#include "executive-config.h" 52#include "cvmx-config.h" 53#include "cvmx.h" 54#include "cvmx-pko.h" 55#include "cvmx-sysinfo.h" 56#include "cvmx-helper.h" 57 58/** 59 * Internal state of packet output 60 */ 61 62#ifdef CVMX_ENABLE_PKO_FUNCTIONS 63 64/** 65 * Call before any other calls to initialize the packet 66 * output system. This does chip global config, and should only be 67 * done by one core. 68 */ 69 70void cvmx_pko_initialize_global(void) 71{ 72 int i; 73 uint64_t priority = 8; 74 cvmx_pko_pool_cfg_t config; 75 76 /* Set the size of the PKO command buffers to an odd number of 64bit 77 words. This allows the normal two word send to stay aligned and never 78 span a comamnd word buffer. */ 79 config.u64 = 0; 80 config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; 81 config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; 82 83 cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); 84 85 for (i=0; i<CVMX_PKO_MAX_OUTPUT_QUEUES; i++) 86 cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, &priority); 87 88 /* If we aren't using all of the queues optimize PKO's internal memory */ 89 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 90 { 91 int num_interfaces = cvmx_helper_get_number_of_interfaces(); 92 int last_port = cvmx_helper_get_last_ipd_port(num_interfaces-1); 93 int max_queues = cvmx_pko_get_base_queue(last_port) + cvmx_pko_get_num_queues(last_port); 94 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 95 { 96 if (max_queues <= 32) 97 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 98 else if (max_queues <= 64) 99 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 100 } 101 else 102 { 103 if (max_queues <= 64) 104 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); 105 else if (max_queues <= 128) 106 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); 107 } 108 } 109} 110 111/** 112 * This function does per-core initialization required by the PKO routines. 113 * This must be called on all cores that will do packet output, and must 114 * be called after the FPA has been initialized and filled with pages. 115 * 116 * @return 0 on success 117 * !0 on failure 118 */ 119int cvmx_pko_initialize_local(void) 120{ 121 /* Nothing to do */ 122 return 0; 123} 124#endif 125 126/** 127 * Enables the packet output hardware. It must already be 128 * configured. 129 */ 130void cvmx_pko_enable(void) 131{ 132 cvmx_pko_reg_flags_t flags; 133 134 flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 135 if (flags.s.ena_pko) 136 cvmx_dprintf("Warning: Enabling PKO when PKO already enabled.\n"); 137 138 flags.s.ena_dwb = 1; 139 flags.s.ena_pko = 1; 140 flags.s.store_be =1; /* always enable big endian for 3-word command. Does nothing for 2-word */ 141 cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); 142} 143 144 145/** 146 * Disables the packet output. Does not affect any configuration. 147 */ 148void cvmx_pko_disable(void) 149{ 150 cvmx_pko_reg_flags_t pko_reg_flags; 151 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 152 pko_reg_flags.s.ena_pko = 0; 153 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 154} 155 156 157#ifdef CVMX_ENABLE_PKO_FUNCTIONS 158/** 159 * @INTERNAL 160 * Reset the packet output. 161 */ 162static void __cvmx_pko_reset(void) 163{ 164 cvmx_pko_reg_flags_t pko_reg_flags; 165 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); 166 pko_reg_flags.s.reset = 1; 167 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); 168} 169 170 171/** 172 * Shutdown and free resources required by packet output. 173 */ 174void cvmx_pko_shutdown(void) 175{ 176 cvmx_pko_queue_cfg_t config; 177 int queue; 178 179 cvmx_pko_disable(); 180 181 for (queue=0; queue<CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) 182 { 183 config.u64 = 0; 184 config.s.tail = 1; 185 config.s.index = 0; 186 config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; 187 config.s.queue = queue & 0x7f; 188 config.s.qos_mask = 0; 189 config.s.buf_ptr = 0; 190 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 191 { 192 cvmx_pko_reg_queue_ptrs1_t config1; 193 config1.u64 = 0; 194 config1.s.qid7 = queue >> 7; 195 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 196 } 197 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 198 cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); 199 } 200 __cvmx_pko_reset(); 201} 202 203 204/** 205 * Configure a output port and the associated queues for use. 206 * 207 * @param port Port to configure. 208 * @param base_queue First queue number to associate with this port. 209 * @param num_queues Number of queues to associate with this port 210 * @param priority Array of priority levels for each queue. Values are 211 * allowed to be 0-8. A value of 8 get 8 times the traffic 212 * of a value of 1. A value of 0 indicates that no rounds 213 * will be participated in. These priorities can be changed 214 * on the fly while the pko is enabled. A priority of 9 215 * indicates that static priority should be used. If static 216 * priority is used all queues with static priority must be 217 * contiguous starting at the base_queue, and lower numbered 218 * queues have higher priority than higher numbered queues. 219 * There must be num_queues elements in the array. 220 */ 221cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, uint64_t num_queues, const uint64_t priority[]) 222{ 223 cvmx_pko_status_t result_code; 224 uint64_t queue; 225 cvmx_pko_queue_cfg_t config; 226 cvmx_pko_reg_queue_ptrs1_t config1; 227 int static_priority_base = -1; 228 int static_priority_end = -1; 229 230 231 if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) 232 { 233 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", (unsigned long long)port); 234 return CVMX_PKO_INVALID_PORT; 235 } 236 237 if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) 238 { 239 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", (unsigned long long)(base_queue + num_queues)); 240 return CVMX_PKO_INVALID_QUEUE; 241 } 242 243 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 244 { 245 /* Validate the static queue priority setup and set static_priority_base and static_priority_end 246 ** accordingly. */ 247 for (queue = 0; queue < num_queues; queue++) 248 { 249 /* Find first queue of static priority */ 250 if (static_priority_base == -1 && priority[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 251 static_priority_base = queue; 252 /* Find last queue of static priority */ 253 if (static_priority_base != -1 && static_priority_end == -1 && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && queue) 254 static_priority_end = queue - 1; 255 else if (static_priority_base != -1 && static_priority_end == -1 && queue == num_queues - 1) 256 static_priority_end = queue; /* all queues are static priority */ 257 /* Check to make sure all static priority queues are contiguous. Also catches some cases of 258 ** static priorites not starting at queue 0. */ 259 if (static_priority_end != -1 && (int)queue > static_priority_end && priority[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY) 260 { 261 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority queues aren't contiguous or don't start at base queue. q: %d, eq: %d\n", (int)queue, static_priority_end); 262 return CVMX_PKO_INVALID_PRIORITY; 263 } 264 } 265 if (static_priority_base > 0) 266 { 267 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority queues don't start at base queue. sq: %d\n", static_priority_base); 268 return CVMX_PKO_INVALID_PRIORITY; 269 } 270#if 0 271 cvmx_dprintf("Port %d: Static priority queue base: %d, end: %d\n", port, static_priority_base, static_priority_end); 272#endif 273 } 274 /* At this point, static_priority_base and static_priority_end are either both -1, 275 ** or are valid start/end queue numbers */ 276 277 result_code = CVMX_PKO_SUCCESS; 278 279#ifdef PKO_DEBUG 280 cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues, CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); 281#endif 282 283 for (queue = 0; queue < num_queues; queue++) 284 { 285 uint64_t *buf_ptr = NULL; 286 287 config1.u64 = 0; 288 config1.s.idx3 = queue >> 3; 289 config1.s.qid7 = (base_queue + queue) >> 7; 290 291 config.u64 = 0; 292 config.s.tail = queue == (num_queues - 1); 293 config.s.index = queue; 294 config.s.port = port; 295 config.s.queue = base_queue + queue; 296 297 if (!cvmx_octeon_is_pass1()) 298 { 299 config.s.static_p = static_priority_base >= 0; 300 config.s.static_q = (int)queue <= static_priority_end; 301 config.s.s_tail = (int)queue == static_priority_end; 302 } 303 /* Convert the priority into an enable bit field. Try to space the bits 304 out evenly so the packet don't get grouped up */ 305 switch ((int)priority[queue]) 306 { 307 case 0: config.s.qos_mask = 0x00; break; 308 case 1: config.s.qos_mask = 0x01; break; 309 case 2: config.s.qos_mask = 0x11; break; 310 case 3: config.s.qos_mask = 0x49; break; 311 case 4: config.s.qos_mask = 0x55; break; 312 case 5: config.s.qos_mask = 0x57; break; 313 case 6: config.s.qos_mask = 0x77; break; 314 case 7: config.s.qos_mask = 0x7f; break; 315 case 8: config.s.qos_mask = 0xff; break; 316 case CVMX_PKO_QUEUE_STATIC_PRIORITY: 317 if (!cvmx_octeon_is_pass1()) /* Pass 1 will fall through to the error case */ 318 { 319 config.s.qos_mask = 0xff; 320 break; 321 } 322 default: 323 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid priority %llu\n", (unsigned long long)priority[queue]); 324 config.s.qos_mask = 0xff; 325 result_code = CVMX_PKO_INVALID_PRIORITY; 326 break; 327 } 328 329 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) 330 { 331 cvmx_cmd_queue_result_t cmd_res = cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO(base_queue + queue), 332 CVMX_PKO_MAX_QUEUE_DEPTH, 333 CVMX_FPA_OUTPUT_BUFFER_POOL, 334 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST*8); 335 if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) 336 { 337 switch (cmd_res) 338 { 339 case CVMX_CMD_QUEUE_NO_MEMORY: 340 cvmx_dprintf("ERROR: cvmx_pko_config_port: Unable to allocate output buffer.\n"); 341 return(CVMX_PKO_NO_MEMORY); 342 case CVMX_CMD_QUEUE_ALREADY_SETUP: 343 cvmx_dprintf("ERROR: cvmx_pko_config_port: Port already setup.\n"); 344 return(CVMX_PKO_PORT_ALREADY_SETUP); 345 case CVMX_CMD_QUEUE_INVALID_PARAM: 346 default: 347 cvmx_dprintf("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n"); 348 return(CVMX_PKO_CMD_QUEUE_INIT_ERROR); 349 } 350 } 351 352 buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO(base_queue + queue)); 353 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); 354 } 355 else 356 config.s.buf_ptr = 0; 357 358 CVMX_SYNCWS; 359 360 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) 361 { 362 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); 363 } 364 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); 365 } 366 367 return result_code; 368} 369 370#ifdef PKO_DEBUG 371/** 372 * Show map of ports -> queues for different cores. 373 */ 374void cvmx_pko_show_queue_map() 375{ 376 int core, port; 377 int pko_output_ports = 36; 378 379 cvmx_dprintf("port"); 380 for(port=0; port<pko_output_ports; port++) 381 cvmx_dprintf("%3d ", port); 382 cvmx_dprintf("\n"); 383 384 for(core=0; core<CVMX_MAX_CORES; core++) 385 { 386 cvmx_dprintf("\n%2d: ", core); 387 for(port=0; port<pko_output_ports; port++) 388 { 389 cvmx_dprintf("%3d ", cvmx_pko_get_base_queue_per_core(port, core)); 390 } 391 } 392 cvmx_dprintf("\n"); 393} 394#endif 395 396 397/** 398 * Rate limit a PKO port to a max packets/sec. This function is only 399 * supported on CN51XX and higher, excluding CN58XX. 400 * 401 * @param port Port to rate limit 402 * @param packets_s Maximum packet/sec 403 * @param burst Maximum number of packets to burst in a row before rate 404 * limiting cuts in. 405 * 406 * @return Zero on success, negative on failure 407 */ 408int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) 409{ 410 cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 411 cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 412 413 pko_mem_port_rate0.u64 = 0; 414 pko_mem_port_rate0.s.pid = port; 415 pko_mem_port_rate0.s.rate_pkt = cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16; 416 /* No cost per word since we are limited by packets/sec, not bits/sec */ 417 pko_mem_port_rate0.s.rate_word = 0; 418 419 pko_mem_port_rate1.u64 = 0; 420 pko_mem_port_rate1.s.pid = port; 421 pko_mem_port_rate1.s.rate_lim = ((uint64_t)pko_mem_port_rate0.s.rate_pkt * burst) >> 8; 422 423 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 424 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 425 return 0; 426} 427 428 429/** 430 * Rate limit a PKO port to a max bits/sec. This function is only 431 * supported on CN51XX and higher, excluding CN58XX. 432 * 433 * @param port Port to rate limit 434 * @param bits_s PKO rate limit in bits/sec 435 * @param burst Maximum number of bits to burst before rate 436 * limiting cuts in. 437 * 438 * @return Zero on success, negative on failure 439 */ 440int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) 441{ 442 cvmx_pko_mem_port_rate0_t pko_mem_port_rate0; 443 cvmx_pko_mem_port_rate1_t pko_mem_port_rate1; 444 uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz; 445 uint64_t tokens_per_bit = clock_rate*16 / bits_s; 446 447 pko_mem_port_rate0.u64 = 0; 448 pko_mem_port_rate0.s.pid = port; 449 /* Each packet has a 12 bytes of interframe gap, an 8 byte preamble, and a 450 4 byte CRC. These are not included in the per word count. Multiply 451 by 8 to covert to bits and divide by 256 for limit granularity */ 452 pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; 453 /* Each 8 byte word has 64bits */ 454 pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; 455 456 pko_mem_port_rate1.u64 = 0; 457 pko_mem_port_rate1.s.pid = port; 458 pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; 459 460 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); 461 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); 462 return 0; 463} 464 465#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 466 467